Compare commits

...

117 Commits
v5.5 ... v6.1.2

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
Aurora
4f8c66b2b7 There would not be an use for this 2016-08-16 22:59:25 +02:00
Aurora
4d9cbc4e19 Fix fail 2016-08-16 22:46:41 +02:00
Aurora
40369d44df Pin cleanup 2016-08-16 22:39:02 +02:00
Aurora
ee3720f0b7 Make loader more readable, use an array instead of a fixed location for the emuNAND test sector 2016-08-16 18:47:27 +02:00
Aurora
e5dcca1c2b Update gitignore 2016-08-16 01:59:23 +02:00
TuxSH
a381c2a811 Update config.c 2016-08-15 21:37:25 +02:00
TuxSH
eef30ceb3c Make the multi-choice options look cleaner 2016-08-15 21:25:06 +02:00
TuxSH
a1024c288e Update pin.c 2016-08-15 17:15:16 +02:00
TuxSH
d445b20e90 Fix bugs 2016-08-15 16:50:58 +02:00
Aurora
bb117d3d74 Clear screens before turning on the backlight to mitigate previous FB contents persisting 2016-08-15 15:25:44 +02:00
Aurora
c101653077 Clear screens before a power off/reboot 2016-08-15 14:46:33 +02:00
Aurora
5248b96f8a No need for this 2016-08-15 13:41:52 +02:00
Aurora
7ab59e420a Fix comment 2016-08-15 13:28:43 +02:00
Aurora
83a849126a Move stuff from firm.c (2) 2016-08-15 13:23:27 +02:00
Aurora
c9c373f607 Move stuff from firm.c 2016-08-15 13:11:27 +02:00
Aurora
aa7c2c0009 Various changes/cleanups, removed useless code, simplified chronometer functions 2016-08-15 03:51:48 +02:00
TuxSH
75acdc8a98 Fix setRSAMod0DerivedKeys 2016-08-14 23:32:56 +02:00
TuxSH
9b304404f7 Enable access to the ITCM (older k9lh payloads disabled access to it).
Thanks @Normmatt for reporting that bug.
2016-08-14 12:30:12 +02:00
TuxSH
95ef379ac5 Remove the empty "luma" folder from the output folder since it will be created automatically when running Luma3DS. 2016-08-13 23:56:07 +02:00
TuxSH
3bc966f84e Replace "Enable splash screen with no screen-init" by "Display splash screen before payloads".
The screens will be initied if and only if there are splash files to display.
2016-08-13 22:23:14 +02:00
TuxSH
457b4cec13 Disable interrupts and do some refactoring. 2016-08-13 20:49:40 +02:00
TuxSH
905777466d Don't set retail keys on dev units. 2016-08-06 22:38:06 +02:00
TuxSH
18b5cdcddf Don't make any assumption regarding version when loading an external firmware file. 2016-08-04 00:05:01 +02:00
TuxSH
389a169443 pin.c cleanup 2016-08-03 20:49:10 +02:00
TuxSH
e01802e299 Check the PIN before loading a payload.
Also fix some bugs.
2016-08-03 16:58:03 +02:00
TuxSH
709aefba5d Implement a PIN-checking system.
Idea and original code by @reworks
2016-08-03 14:13:26 +02:00
Aurora
e4ed713fce Update FatFs to 0.12a 2016-07-20 15:07:13 +02:00
Aurora
d3c507b0d4 Minor stuff 2016-07-20 00:11:59 +02:00
Aurora
a68e14def3 Added error screen when booting an unsupported NAND with no firmware.bin or writing to the config fails, added code for creating the "luma" directory if it is missing 2016-07-18 23:07:28 +02:00
Aurora
8175642a2a Fix changing the brightness
Needs to be static for some reason
2016-07-18 21:57:31 +02:00
Aurora
8d1befea9e Rename "Updated SysNAND" to reflect its only new purpose 2016-07-18 19:10:41 +02:00
Aurora
e7b8a0ef39 Force A9LH detection is not needed anymore 2016-07-18 18:53:23 +02:00
Aurora
be6ee894f9 Fix firmware.bin loading 2016-07-18 17:28:04 +02:00
Aurora
e0e8ed2113 Hardcode 9.6 FIRM version for firmware.bin 2016-07-18 17:13:46 +02:00
Aurora
c63e46b1a9 Added FIRM version detection, removed firmware.bin loading unless an unsupported O3DS NATIVE_FIRM (pre-5.0) is being loaded, skip patching old unsupported O3DS AGB/TWL FIRMs, only apply 11.0 patches with 11.0 or greater 2016-07-18 16:58:29 +02:00
Aurora
eb9c74a1ed Bool-ify 2016-07-18 15:46:29 +02:00
Aurora
efd83e063e Remove code to skip the rbeoot patch on 9.0 as it is not needed anymore with A9LH and constitutes a brick risk 2016-07-18 15:40:31 +02:00
Aurora
ae23a1c84d Fixed Luma allowing users to go to the configuration after AGB_FIRM quits 2016-07-18 15:09:04 +02:00
TuxSH
a0e8bc1de3 Add support for launching >= 6.x/7.x emuNANDs properly when the sysNAND is on a lower firmware version
To launch 3.x - 4.x emuNANDs, you'll need to use an external firmware file (10.x or so should do the trick)
2016-07-14 21:20:45 +02:00
TuxSH
72caad86cc Minor stuff 2016-07-05 16:05:53 +02:00
TuxSH
575adcbb9d Revert part of 136e0d89 (due to cache issues) 2016-07-03 20:53:13 +02:00
TuxSH
53d2aac2ae Update CakeBrah 2016-07-02 17:38:33 +02:00
TuxSH
96211813e3 Use bool instead of u32 where it's relevant 2016-07-02 14:44:01 +02:00
TuxSH
730e716f0f Update CakeBrah 2016-07-02 12:32:39 +02:00
TuxSH
2238293c0f Fix indentation 2016-07-02 10:59:21 +02:00
Aurora
29d8e637d8 One-liners ftw 2016-07-01 20:36:43 +02:00
Aurora
136e0d8974 Cleanup 2016-07-01 20:27:28 +02:00
TuxSH
61684ecb68 We need to clean and flush caches before jumping to payloads, actually. 2016-06-14 19:50:38 +02:00
TuxSH
159c9cb475 Implement our own DCache cleaning functions 2016-06-13 21:14:53 +02:00
TuxSH
2943dcb2e9 Refactor firm.c as well as other files 2016-06-12 22:14:52 +02:00
TuxSH
edfd63e1f7 We don't need to flush DCache when launching payloads.
Fixes a derp as well.
2016-06-10 23:33:03 +02:00
TuxSH
e593584a47 Move screen management code to screen.c and fix cache-related issues
- Screen brightness is now updated as soon as the user selects a brightness option, on all boot environments
- Payloads can now be 1KB bigger
- Some cache-related bugs may have been fixed
2016-06-10 21:48:22 +02:00
TuxSH
f78dd5365c External .code section loading for titles and some refactoring 2016-06-05 20:43:49 +02:00
TuxSH
ae1033d975 Update start.s (thanks @delebile and/or @d0k3) 2016-05-28 23:47:30 +02:00
65 changed files with 3605 additions and 1874 deletions

4
.gitignore vendored
View File

@@ -1,12 +1,12 @@
out out
build build
loader/build loader/build
screeninit/build
injector/build injector/build
exceptions/arm9/build
exceptions/arm11/build
*.bin *.bin
*.3dsx *.3dsx
*.smdh *.smdh
*.o *.o
*.d *.d
*.elf *.elf
*.bat

View File

@@ -13,11 +13,11 @@ OC := arm-none-eabi-objcopy
name := Luma3DS name := Luma3DS
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i') 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_source := source
dir_patches := patches dir_patches := patches
dir_loader := loader dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector dir_injector := injector
dir_mset := CakeHax dir_mset := CakeHax
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
@@ -33,7 +33,8 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c))) $(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/injector.h $(dir_build)/loader.h $(dir_build)/screeninit.h bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/injector.h \
$(dir_build)/loader.h
.PHONY: all .PHONY: all
all: launcher a9lh ninjhax all: launcher a9lh ninjhax
@@ -55,12 +56,11 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean @$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build) @rm -rf $(dir_out) $(dir_build) exceptions
$(dir_out): $(dir_out):
@mkdir -p "$(dir_out)/luma/payloads" @mkdir -p "$(dir_out)"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) $(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher @$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@@ -93,6 +93,11 @@ $(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
@armips $< @armips $<
@bin2c -o $@ -n reboot $(@D)/reboot.bin @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 $(dir_build)/injector.h: $(dir_injector)/Makefile
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@$(MAKE) -C $(dir_injector) @$(MAKE) -C $(dir_injector)
@@ -102,12 +107,9 @@ $(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader) @$(MAKE) -C $(dir_loader)
@bin2c -o $@ -n loader $(@D)/loader.bin @bin2c -o $@ -n loader $(@D)/loader.bin
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile $(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
@$(MAKE) -C $(dir_screeninit)
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
$(dir_build)/memory.o: CFLAGS += -O3
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\"" $(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) $(dir_build)/%.o: $(dir_source)/%.c $(bundled)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"

View File

@@ -22,13 +22,13 @@ LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft ASFLAGS := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \ 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 -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, \ objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.c)) $(call rwildcard, $(dir_source), *.s *.c))
.PHONY: all .PHONY: all
all: ../$(dir_build)/$(name).cxi all: ../$(dir_build)/$(name).cxi
@@ -48,4 +48,8 @@ $(dir_build)/memory.o : CFLAGS += -O3
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d) 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 "memory.h"
#include "patcher.h" #include "patcher.h"
#include "ifile.h" #include "ifile.h"
#include "CFWInfo.h"
#ifndef PATH_MAX static CFWInfo info;
#define PATH_MAX 255
#define CONFIG(a) ((loadConfig() >> (a + 16)) & 1)
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
#endif
static int memcmp(const void *buf1, const void *buf2, u32 size) static int memcmp(const void *buf1, const void *buf2, u32 size)
{ {
@@ -90,39 +86,72 @@ static int fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int f
return IFile_Open(file, archiveId, archivePath, filePath, flags); return IFile_Open(file, archiveId, archivePath, filePath, flags);
} }
static u32 secureInfoExists(void) static void loadCFWInfo(void)
{ {
static u32 secureInfoExists = 0; static bool infoLoaded = false;
if(!secureInfoExists) 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;
if(!exists)
{ {
IFile file; IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ))) if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
{ {
secureInfoExists = 1; exists = true;
IFile_Close(&file); IFile_Close(&file);
} }
} }
return secureInfoExists; return exists;
} }
static u32 loadConfig(void) static void progIdToStr(char *strEnd, u64 progId)
{ {
static u32 config = 0; while(progId)
{
static const char hexDigits[] = "0123456789ABCDEF";
*strEnd-- = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
}
if(!config) static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
{ {
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
If it exists it should be a decompressed binary code file */
char path[] = "/luma/code_sections/0000000000000000.bin";
progIdToStr(path + 35, progId);
IFile file; IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ))) Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret))
{
u64 fileSize;
ret = IFile_GetSize(&file, &fileSize);
if(R_SUCCEEDED(ret) && fileSize <= size)
{ {
u64 total; u64 total;
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4; ret = IFile_Read(&file, &total, code, fileSize);
IFile_Close(&file); IFile_Close(&file);
} }
} }
return config;
} }
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
@@ -131,15 +160,7 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
If it exists it should contain, for example, "EUR IT" */ If it exists it should contain, for example, "EUR IT" */
char path[] = "/luma/locales/0000000000000000.txt"; char path[] = "/luma/locales/0000000000000000.txt";
progIdToStr(path + 29, progId);
u32 i = 29;
while(progId)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
IFile file; IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ); Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
@@ -236,8 +257,8 @@ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetC
if(instr[3] == 0xEB) //We're looking for BL if(instr[3] == 0xEB) //We're looking for BL
{ {
u8 *calledFunction = instr; u8 *calledFunction = instr;
u32 i = 0, u32 i = 0;
found; bool found;
do do
{ {
@@ -292,6 +313,8 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
void patchCode(u64 progId, u8 *code, u32 size) void patchCode(u64 progId, u8 *code, u32 size)
{ {
loadCFWInfo();
switch(progId) switch(progId)
{ {
case 0x0004003000008F02LL: // USA Menu case 0x0004003000008F02LL: // USA Menu
@@ -302,7 +325,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x000400300000B102LL: // TWN Menu case 0x000400300000B102LL: // TWN Menu
{ {
static const u8 regionFreePattern[] = { static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0
}; };
static const u8 regionFreePatch[] = { static const u8 regionFreePatch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
@@ -337,7 +360,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
); );
//Apply only if the updated NAND hasn't been booted //Apply only if the updated NAND hasn't been booted
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(3, 1) && CONFIG(1))) if((BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0 && CONFIG_USESYSFIRM))
{ {
static const u8 skipEshopUpdateCheckPattern[] = { static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0 0x30, 0xB5, 0xF1, 0xB0
@@ -361,7 +384,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004013000003202LL: // FRIENDS case 0x0004013000003202LL: // FRIENDS
{ {
static const u8 fpdVerPattern[] = { static const u8 fpdVerPattern[] = {
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01
}; };
static const u8 mostRecentFpdVer = 0x06; static const u8 mostRecentFpdVer = 0x06;
@@ -381,7 +404,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET case 0x0004001000028000LL: // TWN MSET
{ {
if(CONFIG(5)) if(CONFIG_SHOWNAND)
{ {
static const u16 verPattern[] = u"Ver."; static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3); const u32 currentNand = BOOTCONFIG(0, 3);
@@ -417,12 +440,12 @@ void patchCode(u64 progId, u8 *code, u32 size)
sizeof(stopCartUpdatesPatch), 2 sizeof(stopCartUpdatesPatch), 2
); );
u32 cpuSetting = MULTICONFIG(1); u32 cpuSetting = CONFIG_NEWCPU;
if(cpuSetting) if(cpuSetting)
{ {
static const u8 cfgN3dsCpuPattern[] = { static const u8 cfgN3dsCpuPattern[] = {
0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00 0x00, 0x40, 0xA0, 0xE1, 0x07
}; };
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern)); u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
@@ -441,7 +464,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004013000001702LL: // CFG case 0x0004013000001702LL: // CFG
{ {
static const u8 secureinfoSigCheckPattern[] = { static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC 0x06, 0x46, 0x10, 0x48
}; };
static const u8 secureinfoSigCheckPatch[] = { static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26 0x00, 0x26
@@ -516,12 +539,15 @@ void patchCode(u64 progId, u8 *code, u32 size)
} }
default: default:
if(CONFIG(4)) if(CONFIG_USELANGEMUANDCODE)
{ {
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24; u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
if(tidHigh == 0x0004000) if(tidHigh == 0x0004000)
{ {
//External .code section loading
loadTitleCodeSection(progId, code, size);
//Language emulation //Language emulation
u8 regionId = 0xFF, u8 regionId = 0xFF,
languageId = 0xFF; languageId = 0xFF;

View File

@@ -2,4 +2,18 @@
#include <3ds/types.h> #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); void patchCode(u64 progId, u8 *code, u32 size);

View File

@@ -1,7 +1,7 @@
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x24FFFB00; . = 0x24FFFF00;
.text.start : { *(.text.start) } .text.start : { *(.text.start) }
.text : { *(.text) } .text : { *(.text) }
.data : { *(.data) } .data : { *(.data) }

27
loader/source/cache.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* 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"
void flushCaches(void);

52
loader/source/cache.s Normal file
View File

@@ -0,0 +1,52 @@
@ 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
.global flushCaches
.type flushCaches STT_FUNC
flushCaches:
@ Clean and flush data cache
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
@ Implemented in bootROM at address 0xffff0830
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
@ Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
bx lr

View File

@@ -1,10 +1,37 @@
/*
* 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 "memory.h" #include "memory.h"
#include "cache.h"
extern u32 payloadSize; //Defined in start.s
void main(void) void main(void)
{ {
void *payloadAddress = (void *)0x23F00000; void *payloadAddress = (void *)0x23F00000;
memcpy(payloadAddress, (void*)0x24F00000, *(u32 *)0x24FFFB04); memcpy(payloadAddress, (void*)0x24F00000, payloadSize);
flushCaches();
((void (*)())payloadAddress)(); ((void (*)())payloadAddress)();
} }

View File

@@ -1,3 +1,30 @@
/*
* 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.
*/
/*
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#include "memory.h" #include "memory.h"
void memcpy(void *dest, const void *src, u32 size) void memcpy(void *dest, const void *src, u32 size)

View File

@@ -1,3 +1,30 @@
/*
* 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.
*/
/*
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#pragma once #pragma once
#include "types.h" #include "types.h"

View File

@@ -1,16 +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.
.section .text.start .section .text.start
.align 4 .align 4
.global _start .global _start
_start: _start:
b start
.word 0
start:
@ Flush caches
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
b main b main
.global payloadSize
payloadSize:
.word 0

View File

@@ -1,3 +1,25 @@
/*
* 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 #pragma once
#include <stdint.h> #include <stdint.h>

View File

@@ -1,14 +1,18 @@
.arm.little .arm.little
payload_addr equ 0x23F00000 ; Brahma payload address. payload_addr equ 0x23F00000 ; Brahma payload address.
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do). payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeBrah supports).
.create "build/reboot.bin", 0 .create "build/reboot.bin", 0
.arm .arm
; Interesting registers and locations to keep in mind, set before this code is ran: ; Interesting registers and locations to keep in mind, set just before this code is ran:
; - sp + 0x3A8 - 0x70: FIRM path in exefs. ; - r1: FIRM path in exefs.
; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle ; - r7: pointer to file object
; - *(sp + 0x3A8 - 0x198) + 0x28: fread function. ; - *r7: vtable
; - *(vtable + 0x28): fread function
; - *(r7 + 8): file handle
mov r8, r1
pxi_wait_recv: pxi_wait_recv:
ldr r2, =0x44846 ldr r2, =0x44846
@@ -47,20 +51,22 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
cmp r4, #0 cmp r4, #0
movne r3, #0x12000 ; Skip the first 0x12000 bytes. movne r3, #0x12000 ; Skip the first 0x12000 bytes.
moveq r3, payload_maxsize moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198] ldr r6, [r7]
ldr r6, [r6, #0x28] ldr r6, [r6, #0x28]
blx r6 blx r6
cmp r4, #0 cmp r4, #0
movne r4, #0 movne r4, #0
bne read_payload ; Go read the real payload. bne read_payload ; Go read the real payload.
; Copy the last digits of the wanted firm to the 5th byte of the payload ; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
add r2, sp, #0x3A8 - 0x70 add r0, r8, 0x1A
ldr r0, [r2, #0x27] add r1, r0, #0x10
ldr r1, =payload_addr + 4 ldr r2, =payload_addr + 4
str r0, [r1] copy_TID_low:
ldr r0, [r2, #0x2B] ldrh r3, [r0], #2
str r0, [r1, #4] strh r3, [r2], #2
cmp r0, r1
blo copy_TID_low
; Set kernel state ; Set kernel state
mov r0, #0 mov r0, #0
@@ -72,7 +78,7 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
goto_reboot: goto_reboot:
; Jump to reboot code ; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12) 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 swi 0x7B
die: die:
@@ -88,61 +94,32 @@ dat_fname: .dcw "sdmc:/Luma3DS.dat"
.align 4 .align 4
kernelcode_start: 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)
mrc p15, 0, r0, c2, c0, 0 ; dcacheable ; Disable MPU
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
; 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 ldr r0, =0x42078 ; alt vector select, enable itcm
mcr p15, 0, r0, c1, c0, 0 mcr p15, 0, r0, c1, c0, 0
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
mcr p15, 0, r1, c7, c6, 0 ; flush icache ; Clean and flush data cache
mov r1, #0 ; segment counter
outer_loop:
mov r0, #0 ; line counter
inner_loop:
orr r2, r1, r0 ; generate segment and line address
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
add r0, #0x20 ; increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
; Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
; Jump to payload ; Jump to payload
ldr r0, =payload_addr ldr r0, =payload_addr
bx r0 bx r0

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

@@ -1,47 +0,0 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: ../$(dir_build)/$(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(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)

View File

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

View File

@@ -1,105 +0,0 @@
#include "types.h"
void main(void)
{
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
u32 brightnessLevel = *(vu32 *)0x24FFFC08;
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

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

View File

@@ -1,13 +0,0 @@
#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;

View File

@@ -1,5 +1,23 @@
/* /*
* buttons.h * 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 #pragma once
@@ -10,7 +28,7 @@
#define BUTTON_R1 (1 << 8) #define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9) #define BUTTON_L1 (1 << 9)
#define BUTTON_A 1 #define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1) #define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10) #define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11) #define BUTTON_Y (1 << 11)
@@ -25,3 +43,4 @@
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y) #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 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 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_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START)

39
source/cache.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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"
/***
The following functions flush the data cache, then waits for all memory transfers to be finished.
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
- rebooting
- powering down
- setting the ARM11 entrypoint to execute a function
- jumping to a payload
***/
void flushEntireDCache(void); //actually: "clean and flush"
void flushDCacheRange(void *startAddress, u32 size);
void flushEntireICache(void);
void flushICacheRange(void *startAddress, u32 size);

89
source/cache.s Normal file
View File

@@ -0,0 +1,89 @@
@ 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.
.text
.arm
.align 4
.global flushEntireDCache
.type flushEntireDCache, %function
flushEntireDCache:
@ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
@ Implemented in bootROM at address 0xffff0830
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
bx lr
.global flushDCacheRange
.type flushDCacheRange, %function
flushDCacheRange:
@ Implemented in bootROM at address 0xffff08a0
add r1, r0, r1 @ end address
bic r0, #0x1f @ align source address to cache line size (32 bytes)
flush_dcache_range_loop:
mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
add r0, #0x20
cmp r0, r1
blo flush_dcache_range_loop
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
bx lr
.global flushEntireICache
.type flushEntireICache, %function
flushEntireICache:
@ Implemented in bootROM at address 0xffff0ab4
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
.global flushICacheRange
.type flushICacheRange, %function
flushICacheRange:
@ Implemented in bootROM at address 0xffff0ac0
add r1, r0, r1 @ end address
bic r0, #0x1f @ align source address to cache line size (32 bytes)
flush_icache_range_loop:
mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding
add r0, #0x20
cmp r0, r1
blo flush_icache_range_loop
bx lr

View File

@@ -1,40 +1,95 @@
/* /*
* config.c * 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 "config.h" #include "config.h"
#include "utils.h" #include "memory.h"
#include "screeninit.h"
#include "draw.h"
#include "fs.h" #include "fs.h"
#include "i2c.h" #include "utils.h"
#include "screen.h"
#include "draw.h"
#include "buttons.h" #include "buttons.h"
#include "pin.h"
void configureCFW(const char *configPath) bool readConfig(void)
{ {
u32 needToDeinit = initScreens(); 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();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE); drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )", const char *multiOptionsText[] = { "Screen brightness: 4( ) 3( ) 2( ) 1( )",
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" }; "New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND", const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) SysNAND is updated (A9LH-only)", "( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Force A9LH detection",
"( ) Use second EmuNAND as default", "( ) Use second EmuNAND as default",
"( ) Enable region/language emulation", "( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings", "( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Enable splash screen with no screen-init" }; "( ) Display splash screen before payloads" };
struct multiOption { struct multiOption {
int posXs[4]; int posXs[4];
int posY; int posY;
u32 enabled; u32 enabled;
} multiOptions[] = { } multiOptions[] = {
{ .posXs = {26, 31, 36, 41} }, { .posXs = {21, 26, 31, 36} },
{ .posXs = {14, 19, 24, 29} },
{ .posXs = {17, 26, 32, 44} } { .posXs = {17, 26, 32, 44} }
}; };
@@ -46,7 +101,7 @@ void configureCFW(const char *configPath)
struct singleOption { struct singleOption {
int posY; int posY;
u32 enabled; bool enabled;
} singleOptions[singleOptionsAmount]; } singleOptions[singleOptionsAmount];
//Parse the existing options //Parse the existing options
@@ -145,10 +200,13 @@ void configureCFW(const char *configPath)
u32 oldEnabled = multiOptions[selectedOption].enabled; u32 oldEnabled = multiOptions[selectedOption].enabled;
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK); drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1; multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
if(!selectedOption)
updateBrightness(multiOptions[selectedOption].enabled);
} }
else else
{ {
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled; bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled; singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK); if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
} }
@@ -164,25 +222,22 @@ void configureCFW(const char *configPath)
} }
} }
u32 oldPinLength = CONFIG_PIN;
//Preserve the last-used boot options (last 12 bits) //Preserve the last-used boot options (last 12 bits)
config &= 0x3F; configData.config &= 0x3F;
//Parse and write the new configuration //Parse and write the new configuration
for(u32 i = 0; i < multiOptionsAmount; i++) 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++) for(u32 i = 0; i < singleOptionsAmount; i++)
config |= singleOptions[i].enabled << (i + 16); configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 20);
fileWrite(&config, configPath, 4); if(CONFIG_PIN != 0) newPin(oldPinStatus && CONFIG_PIN == oldPinLength);
else if(oldPinStatus) fileDelete(PIN_PATH);
//Wait for the pressed buttons to change //Wait for the pressed buttons to change
while(HID_PAD == BUTTON_START); while(HID_PAD & PIN_BUTTONS);
if(needToDeinit) chrono(2);
{
//Turn off backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
deinitScreens();
PDN_GPU_CNT = 1;
}
} }

View File

@@ -1,15 +1,67 @@
/* /*
* config.h * 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 #pragma once
#include "types.h" #include "types.h"
#define CONFIG(a) ((config >> (a + 16)) & 1) #define CONFIG(a) (((configData.config >> (a + 20)) & 1) != 0)
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3) #define MULTICONFIG(a) ((configData.config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((config >> a) & b) #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

@@ -1,6 +1,26 @@
/* /*
* crypto.c * 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.
*/
/*
* Crypto libs from http://github.com/b1l1s/ctr * Crypto libs from http://github.com/b1l1s/ctr
*/ */
@@ -274,25 +294,26 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
* NAND/FIRM crypto * NAND/FIRM crypto
****************************************************************/ ****************************************************************/
static u8 nandCTR[0x10], static u8 __attribute__((aligned(4))) nandCTR[0x10];
nandSlot; static u8 nandSlot;
static u32 fatStart; static u32 fatStart;
//Initialize the CTRNAND crypto //Initialize the CTRNAND crypto
void ctrNandInit(void) void ctrNandInit(void)
{ {
u8 cid[0x10]; u8 __attribute__((aligned(4))) cid[0x10];
u8 shaSum[0x20]; u8 __attribute__((aligned(4))) shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid); sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE); sha(shaSum, cid, 0x10, SHA_256_MODE);
memcpy(nandCTR, shaSum, 0x10); memcpy(nandCTR, shaSum, 0x10);
if(console) if(isN3DS)
{ {
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05; nandSlot = 0x05;
fatStart = 0x5CAD7; fatStart = 0x5CAD7;
} }
@@ -306,13 +327,13 @@ void ctrNandInit(void)
//Read and decrypt from the selected CTRNAND //Read and decrypt from the selected CTRNAND
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf) u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{ {
u8 tmpCTR[0x10]; u8 __attribute__((aligned(4))) tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10); memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Read //Read
u32 result; u32 result;
if(!firmSource) if(firmSource == FIRMWARE_SYSNAND)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf); result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else else
{ {
@@ -327,6 +348,24 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
return result; return result;
} }
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
void setRSAMod0DerivedKeys(void)
{
if(!isDevUnit)
{
const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
when non-zero it clears this block and continues to do the key generation.
Otherwise when this block was already all-zero, it immediately returns. */
memset32((void *)0x01FFCD00, 0, 0x10);
}
}
//Decrypt a FIRM ExeFS //Decrypt a FIRM ExeFS
void decryptExeFs(u8 *inbuf) void decryptExeFs(u8 *inbuf)
{ {
@@ -344,13 +383,29 @@ void decryptExeFs(u8 *inbuf)
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
//ARM9Loader replacement /* ARM9Loader replacement
void arm9Loader(u8 *arm9Section, u32 mode) Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 */
void arm9Loader(u8 *arm9Section)
{ {
//Determine the arm9loader version
u32 a9lVersion;
switch(arm9Section[0x53])
{
case 0xFF:
a9lVersion = 0;
break;
case '1':
a9lVersion = 1;
break;
default:
a9lVersion = 2;
break;
}
//Firm keys //Firm keys
u8 keyY[0x10], u8 __attribute__((aligned(4))) keyY[0x10];
arm9BinCTR[0x10], u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
arm9BinSlot = mode ? 0x16 : 0x15; u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
@@ -362,13 +417,18 @@ void arm9Loader(u8 *arm9Section, u32 mode)
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0'; arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
if(mode) if(a9lVersion)
{ {
const u8 key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, u8 __attribute__((aligned(4))) keyX[0x10];
key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
u8 keyX[0x10]; if(!isDevUnit)
{
const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
}
aes_setkey(0x11, mode == 1 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -382,18 +442,28 @@ void arm9Loader(u8 *arm9Section, u32 mode)
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set >=9.6 KeyXs //Set >=9.6 KeyXs
if(mode == 1) if(a9lVersion == 2 && !isDevUnit)
{ {
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}, u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
decKey[0x10]; u8 __attribute__((aligned(4))) decKey[0x10];
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++) for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
{ {
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
keyData[0xF] += 1;
} }
} }
} }
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 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

@@ -1,6 +1,26 @@
/* /*
* crypto.h * 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.
*/
/*
* Crypto libs from http://github.com/b1l1s/ctr * Crypto libs from http://github.com/b1l1s/ctr
*/ */
@@ -79,9 +99,13 @@
#define SHA_224_HASH_SIZE (224 / 8) #define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8) #define SHA_1_HASH_SIZE (160 / 8)
extern u32 emuOffset, console, firmSource; extern u32 emuOffset;
extern bool isN3DS, isDevUnit;
extern FirmwareSource firmSource;
void ctrNandInit(void); void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void setRSAMod0DerivedKeys(void);
void decryptExeFs(u8 *inbuf); void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section, u32 mode); void arm9Loader(u8 *arm9Section);
void computePinHash(u8 *out, u8 *in);

View File

@@ -1,47 +1,51 @@
/* /*
* draw.c * 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.
*/
/*
* Code to print to the screen by mid-kid @CakesFW * Code to print to the screen by mid-kid @CakesFW
* https://github.com/mid-kid/CakesForeveryWan/
*/ */
#include "draw.h" #include "draw.h"
#include "screeninit.h" #include "strings.h"
#include "screen.h"
#include "utils.h" #include "utils.h"
#include "fs.h" #include "fs.h"
#include "memory.h"
#include "font.h" #include "font.h"
static const struct fb { bool loadSplash(void)
u8 *top_left;
u8 *top_right;
u8 *bottom;
} *const fb = (struct fb *)0x23FFFE00;
static inline int strlen(const char *string)
{ {
char *stringEnd = (char *)string; //Don't delay boot nor init the screens if no splash image is on the SD
if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splashbottom.bin") == 0)
return false;
while(*stringEnd) stringEnd++;
return stringEnd - string;
}
void clearScreens(void)
{
memset32(fb->top_left, 0, 0x46500);
memset32(fb->top_right, 0, 0x46500);
memset32(fb->bottom, 0, 0x38400);
}
u32 loadSplash(void)
{
initScreens(); initScreens();
//Don't delay boot if no splash image is on the SD fileRead(fb->top_left, "/luma/splash.bin");
if(fileRead(fb->top_left, "/luma/splash.bin") + fileRead(fb->bottom, "/luma/splashbottom.bin");
fileRead(fb->bottom, "/luma/splashbottom.bin"))
return 1; chrono(3);
return 0;
return true;
} }
void drawCharacter(char character, int posX, int posY, u32 color) void drawCharacter(char character, int posX, int posY, u32 color)

View File

@@ -1,7 +1,28 @@
/* /*
* draw.h * 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.
*/
/*
* Code to print to the screen by mid-kid @CakesFW * Code to print to the screen by mid-kid @CakesFW
* https://github.com/mid-kid/CakesForeveryWan/
*/ */
#pragma once #pragma once
@@ -19,7 +40,6 @@
#define COLOR_RED 0x0000FF #define COLOR_RED 0x0000FF
#define COLOR_BLACK 0x000000 #define COLOR_BLACK 0x000000
u32 loadSplash(void); bool loadSplash(void);
void clearScreens(void);
void drawCharacter(char character, int posX, int posY, u32 color); 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);

View File

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

View File

@@ -1,5 +1,23 @@
/* /*
* emunand.h * 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 #pragma once
@@ -8,5 +26,7 @@
#define NCSD_MAGIC 0x4453434E #define NCSD_MAGIC 0x4453434E
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND); extern u32 emuOffset;
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
void locateEmuNand(u32 *off, u32 *head, FirmwareSource *emuNand);
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive);

21
source/fatfs/00history.txt Normal file → Executable file
View File

@@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
R0.01 (April 29, 2006) R0.01 (April 29, 2006)
First stable version. The first release.
@@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
R0.12 (April 12, 2016) R0.12 (April 12, 2016)
Added support of exFAT file system. (_FS_EXFAT) Added support for exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND) Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir(). Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD and removed an option _WORD_ACCESS. Added an option _USE_CHMOD.
Fixed errors in the case conversion teble of Unicode (cc*.c). Removed an option _WORD_ACCESS.
Fixed errors in the case conversion table of Unicode (cc*.c).
R0.12a (July 10, 2016)
Added support for creating exFAT volume with some changes of f_mkfs().
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
f_forward() is available regardless of _FS_TINY.
Fixed f_mkfs() creates wrong volume.
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
Fixed wrong memory read in create_name().

2
source/fatfs/00readme.txt Normal file → Executable file
View File

@@ -1,4 +1,4 @@
FatFs Module Source Files R0.12 FatFs Module Source Files R0.12a
FILES FILES

1507
source/fatfs/ff.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

102
source/fatfs/ff.h Normal file → Executable file
View File

@@ -1,11 +1,13 @@
/*---------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016 / FatFs - Generic FAT file system module R0.12a /
/----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/ /
/ Copyright (C) 2016, ChaN, all right reserved. / Copyright (C) 2016, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice, / 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer. / this condition and the following disclaimer.
/ /
@@ -13,11 +15,11 @@
/ and any warranties related to this software are DISCLAIMED. / and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software. / by use of this software.
/---------------------------------------------------------------------------*/ /----------------------------------------------------------------------------*/
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 88100 /* Revision ID */ #define _FATFS 80186 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -25,6 +27,7 @@ extern "C" {
#include "integer.h" /* Basic integer types */ #include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h). #error Wrong configuration file (ffconf.h).
#endif #endif
@@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */ #if _LFN_UNICODE /* Unicode (UTF-16) string */
#if _USE_LFN == 0 #if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg. #error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif #endif
@@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#endif #endif
#else /* ANSI/OEM string */ #else /* ANSI/OEM string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#endif #endif
#endif
/* Type of file size variables */
#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif #endif
@@ -87,6 +101,9 @@ typedef struct {
#if _MAX_SS != _MIN_SS #if _MAX_SS != _MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif #endif
#if _USE_LFN != 0
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if _FS_EXFAT #if _FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer */ BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif #endif
@@ -117,19 +134,6 @@ typedef struct {
/* Type of file size variables and object identifier */
#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Object ID and allocation information (_FDID) */ /* Object ID and allocation information (_FDID) */
typedef struct { typedef struct {
@@ -159,14 +163,14 @@ typedef struct {
BYTE flag; /* File status flags */ BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */ BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY #if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */ DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif #endif
#if _USE_FASTSEEK #if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif #endif
#if !_FS_TINY #if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */ BYTE buf[_MAX_SS]; /* File private data read/write window */
@@ -183,10 +187,9 @@ typedef struct {
DWORD clust; /* Current cluster */ DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */ DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if _USE_LFN != 0 #if _USE_LFN != 0
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
WCHAR* lfn; /* Pointer to the LFN working buffer */
#endif #endif
#if _USE_FIND #if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */ const TCHAR* pat; /* Pointer to the name matching pattern */
@@ -229,7 +232,7 @@ typedef enum {
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
@@ -244,11 +247,11 @@ typedef enum {
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */ FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
@@ -258,8 +261,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
@@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
@@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
/* Flags and offset address */ /* Flags and offset address */
/* File access control and file status flags (FIL.flag) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01
#define FA_WRITE 0x02 #define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00 #define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04 #define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08 #define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_ALWAYS 0x10
#define _FA_MODIFIED 0x20 #define FA_OPEN_APPEND 0x30
#define _FA_DIRTY 0x40
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* FAT sub type (FATFS.fs_type) */ /* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1 #define FS_FAT12 1
#define FS_FAT16 2 #define FS_FAT16 2
#define FS_FAT32 3 #define FS_FAT32 3
#define FS_EXFAT 4 #define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */ #define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */ #define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */ #define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */ #define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */ #define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek controls */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#ifdef __cplusplus #ifdef __cplusplus

17
source/fatfs/ffconf.h Normal file → Executable file
View File

@@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016 / FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 88100 /* Revision ID */ #define _FFCONF 80186 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@@ -15,7 +15,7 @@
/ and optional writing functions as well. */ / and optional writing functions as well. */
#define _FS_MINIMIZE 1 #define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: All basic functions are enabled.
@@ -62,8 +62,7 @@
#define _USE_FORWARD 0 #define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) /* This option switches f_forward() function. (0:Disable or 1:Enable) */
/ To enable it, also _FS_TINY need to be 1. */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
@@ -118,13 +117,13 @@
#define _LFN_UNICODE 0 #define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ This option also affects behavior of string I/O functions. */ / This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 3 #define _STRF_ENCODE 3
/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to /* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/ /
/ 0: ANSI/OEM / 0: ANSI/OEM
@@ -153,7 +152,7 @@
#define _STR_VOLUME_ID 0 #define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" #define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID. /* _STR_VOLUME_ID switches string support of volume ID.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each / number in the path name. _VOLUME_STRS defines the drive ID strings for each
@@ -217,7 +216,7 @@
#define _FS_NORTC 1 #define _FS_NORTC 1
#define _NORTC_MON 3 #define _NORTC_MON 1
#define _NORTC_MDAY 1 #define _NORTC_MDAY 1
#define _NORTC_YEAR 2016 #define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have /* The option _FS_NORTC switches timestamp functiton. If the system does not have

0
source/fatfs/integer.h Normal file → Executable file
View File

0
source/fatfs/option/ccsbcs.c Normal file → Executable file
View File

View File

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

View File

@@ -1,5 +1,23 @@
/* /*
* firm.c * 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 "firm.h" #include "firm.h"
@@ -8,357 +26,360 @@
#include "fs.h" #include "fs.h"
#include "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "cache.h"
#include "emunand.h" #include "emunand.h"
#include "crypto.h" #include "crypto.h"
#include "draw.h" #include "draw.h"
#include "screeninit.h" #include "screen.h"
#include "buttons.h" #include "buttons.h"
#include "pin.h"
#include "../build/injector.h" #include "../build/injector.h"
extern u16 launchedFirmTidLow[8]; //Defined in start.s
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section; static const firmSectionHeader *section;
u32 config, u32 emuOffset;
console,
firmSource, bool isN3DS,
emuOffset; isDevUnit,
isFirmlaunch;
cfgData configData;
FirmwareSource firmSource;
void main(void) void main(void)
{ {
u32 bootType, bool isA9lh;
firmType,
nandType, u32 configTemp,
a9lhMode, emuHeader;
updatedSys,
needConfig, FirmwareType firmType;
newConfig, FirmwareSource nandType;
emuHeader, ConfigurationStatus needConfig;
chronoStarted = 0;
//Detect the console being used //Detect the console being used
console = PDN_MPCORE_CFG == 7; isN3DS = PDN_MPCORE_CFG == 7;
//Detect dev units
isDevUnit = CFG_UNITINFO != 0;
//Mount filesystems. CTRNAND will be mounted only if/when needed //Mount filesystems. CTRNAND will be mounted only if/when needed
mountFs(); mountFs();
const char configPath[] = "/luma/config.bin";
//Attempt to read the configuration file //Attempt to read the configuration file
needConfig = fileRead(&config, configPath) ? 1 : 2; needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
//Determine if this is a firmlaunch boot //Determine if this is a firmlaunch boot
if(*(vu8 *)0x23F00005) if(launchedFirmTidLow[5] != 0)
{ {
if(needConfig == 2) mcuReboot(); isFirmlaunch = true;
bootType = 1; if(needConfig == CREATE_CONFIGURATION) mcuReboot();
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = *(vu8 *)0x23F00009 == '3' ? 3 : *(vu8 *)0x23F00005 - '0'; firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0');
nandType = BOOTCONFIG(0, 3); nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = BOOTCONFIG(2, 1); firmSource = (FirmwareSource)BOOTCFG_FIRM;
a9lhMode = BOOTCONFIG(3, 1); isA9lh = BOOTCFG_A9LH != 0;
updatedSys = a9lhMode && CONFIG(1);
} }
else else
{ {
isFirmlaunch = false;
firmType = NATIVE_FIRM;
//Determine if booting with A9LH
isA9lh = !PDN_SPI_CNT;
//Get pressed buttons //Get pressed buttons
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
//If no configuration file exists or SELECT is held, load configuration menu //Save old options and begin saving the new boot configuration
if(needConfig == 2 || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1))) configTemp = (configData.config & 0xFFFFFFC0) | ((u32)isA9lh << 3);
//If it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV)
{ {
configureCFW(configPath); //Always force a sysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7)
{
nandType = FIRMWARE_SYSNAND;
firmSource = CONFIG_USESYSFIRM ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
//Zero the last booted FIRM flag //Flag to prevent multiple boot options-forcing
CFG_BOOTENV = 0; configTemp |= 1 << 4;
}
chronoStarted = 1; /* Else, force the last used boot options unless a button is pressed
chrono(0); or the no-forcing flag is set */
chrono(2); else if(needConfig != CREATE_CONFIGURATION && !pressed && !BOOTCFG_NOFORCEFLAG)
{
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
needConfig = DONT_CONFIGURE;
}
}
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
bool pinExists = CONFIG_PIN != 0 && verifyPin();
//If no configuration file exists or SELECT is held, load configuration menu
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
if(shouldLoadConfigMenu)
{
configMenu(pinExists);
//Update pressed buttons //Update pressed buttons
pressed = HID_PAD; pressed = HID_PAD;
} }
bootType = 0; if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
firmType = 0;
//Determine if booting with A9LH
u32 a9lhBoot = !PDN_SPI_CNT;
//Determine if A9LH is installed and the user has an updated sysNAND
if(a9lhBoot || CONFIG(2))
{ {
a9lhMode = 1; nandType = FIRMWARE_SYSNAND;
updatedSys = CONFIG(1); 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 else
{ {
a9lhMode = 0; if(CONFIG_PAYLOADSPLASH && loadSplash()) pressed = HID_PAD;
updatedSys = 0;
}
newConfig = a9lhMode << 3;
if(a9lhBoot)
{
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//If it's a MCU reboot, try to force boot options
if(previousFirm)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 7)
{
nandType = 0;
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
needConfig = 0;
//Flag to prevent multiple boot options-forcing
newConfig |= 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))
{
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
needConfig = 0;
}
}
//If the SAFE MODE combo is held, force a sysNAND boot
else if(pressed == SAFE_MODE)
{
a9lhMode = 2;
nandType = 0;
firmSource = 0;
needConfig = 0;
}
}
//Boot options aren't being forced
if(needConfig)
{
/* If L and R/A/Select or one of the single payload buttons are pressed, /* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload */ chainload an external payload */
if((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS))) bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
loadPayload(pressed);
//If screens are inited or the corresponding option is set, load splash screen if(shouldLoadPayload) loadPayload(pressed);
if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
{ if(!CONFIG_PAYLOADSPLASH) loadSplash();
chronoStarted = 2;
chrono(0); //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 R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1) if(pressed & BUTTON_R1)
{ {
nandType = updatedSys; nandType = useSysAsDefault ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = !nandType; firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
} }
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */ with their own FIRM */
else else
{ {
nandType = CONFIG(0) != !(pressed & BUTTON_L1); nandType = (CONFIG_AUTOBOOTSYS != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = nandType; firmSource = nandType;
} }
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed, /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */ or vice-versa, boot the second emuNAND */
if(nandType && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = 2; if(nandType != FIRMWARE_SYSNAND && (CONFIG_USESECONDEMU == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
}
} }
} }
//If we need to boot emuNAND, make sure it exists //If we need to boot emuNAND, make sure it exists
if(nandType) if(nandType != FIRMWARE_SYSNAND)
{ {
locateEmuNAND(&emuOffset, &emuHeader, &nandType); locateEmuNand(&emuOffset, &emuHeader, &nandType);
if(!nandType) firmSource = 0; if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
} }
//Same if we're using emuNAND as the FIRM source //Same if we're using emuNAND as the FIRM source
else if(firmSource) else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNAND(&emuOffset, &emuHeader, &firmSource); locateEmuNand(&emuOffset, &emuHeader, &firmSource);
if(!bootType) if(!isFirmlaunch)
{ {
newConfig |= nandType | (firmSource << 2); configTemp |= (u32)nandType | ((u32)firmSource << 2);
writeConfig(needConfig, configTemp);
/* 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;
fileWrite(&newConfig, configPath, 4);
}
} }
loadFirm(firmType, !firmType && updatedSys == !firmSource); u32 firmVersion = loadFirm(&firmType, firmSource);
switch(firmType) switch(firmType)
{ {
case 0: case NATIVE_FIRM:
patchNativeFirm(nandType, emuHeader, a9lhMode); patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break; break;
case 3: case SAFE_FIRM:
patchSafeFirm(); case NATIVE_FIRM1X2X:
if(isA9lh) patch1x2xNativeAndSafeFirm();
break; break;
default: default:
patchLegacyFirm(firmType); //Skip patching on unsupported O3DS AGB/TWL FIRMs
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
break; break;
} }
if(chronoStarted) launchFirm(firmType);
{
if(chronoStarted == 2) chrono(3);
stopChrono();
} }
launchFirm(firmType, bootType); static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
}
static inline void loadFirm(u32 firmType, u32 externalFirm)
{ {
section = firm->section; section = firm->section;
u32 externalFirmLoaded = externalFirm && //Load FIRM from CTRNAND
fileRead(firm, "/luma/firmware.bin") && u32 firmVersion = firmRead(firm, (u32)*firmType);
(((u32)section[2].address >> 8) & 0xFF) == (console ? 0x60 : 0x68);
/* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM if(!isN3DS && *firmType == NATIVE_FIRM)
doesn't match the console, load FIRM from CTRNAND */
if(!externalFirmLoaded)
{ {
const char *firmFolders[4][2] = {{ "00000002", "20000002" }, if(firmVersion < 0x18)
{ "00000102", "20000102" }, {
{ "00000202", "20000202" }, //We can't boot < 3.x EmuNANDs
{ "00000003", "20000003" }}; if(firmSource != FIRMWARE_SYSNAND)
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it");
firmRead(firm, firmFolders[firmType][console]); if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM");
decryptExeFs((u8 *)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;
} }
} }
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode) if(firmVersion != 0xFFFFFFFF) decryptExeFs((u8 *)firm);
return firmVersion;
}
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
{ {
u8 *arm9Section = (u8 *)firm + section[2].offset; u8 *arm9Section = (u8 *)firm + section[2].offset;
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
u32 nativeFirmType; if(isN3DS)
if(console)
{ {
//Determine the NATIVE_FIRM version
switch(arm9Section[0x53])
{
case 0xFF:
nativeFirmType = 0;
break;
case '1':
nativeFirmType = 2;
break;
default:
nativeFirmType = 1;
break;
}
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, nativeFirmType); arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; firm->arm9Entry = (u8 *)0x801B01C;
} }
else
{ //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
//Determine if we're booting the 9.0 FIRM else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
nativeFirmType = memcmp(section[2].hash, firm90Hash, 0x10) != 0;
}
//Find the Process9 .code location, size and memory address //Find the Process9 .code location, size and memory address
u32 process9Size, u32 process9Size,
process9MemAddr; process9MemAddr;
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &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 //Apply signature patches
patchSignatureChecks(process9Offset, process9Size); patchSignatureChecks(process9Offset, process9Size);
//Apply emuNAND patches //Apply emuNAND patches
if(nandType) if(nandType != FIRMWARE_SYSNAND)
{ {
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address; 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 //Apply FIRM0/1 writes patches on sysNAND to protect A9LH
else if(a9lhMode) patchFirmWrites(process9Offset, process9Size); else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
//Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax //Apply firmlaunch patches
if(nativeFirmType || a9lhMode == 2) patchFirmlaunches(process9Offset, process9Size, process9MemAddr); patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
if(nativeFirmType == 1) //11.0 FIRM patches
if(firmVersion >= (isN3DS ? 0x21 : 0x52))
{ {
//Apply anti-anti-DG patches for >= 11.0 firmwares //Apply anti-anti-DG patches
patchTitleInstallMinVersionCheck(process9Offset, process9Size); patchTitleInstallMinVersionCheck(process9Offset, process9Size);
//Does nothing if svcBackdoor is still there //Restore svcBackdoor
reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size); reimplementSvcBackdoor(arm11Section1, arm11SvcTable, &freeK11Space);
}
} }
static inline void patchLegacyFirm(u32 firmType) implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, &freeK11Space);
}
static inline void patchLegacyFirm(FirmwareType firmType)
{ {
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader if(isN3DS)
if(console)
{ {
arm9Loader((u8 *)firm + section[3].offset, 0); //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader((u8 *)firm + section[3].offset);
firm->arm9Entry = (u8 *)0x801301C; firm->arm9Entry = (u8 *)0x801301C;
} }
applyLegacyFirmPatches((u8 *)firm, firmType, console); applyLegacyFirmPatches((u8 *)firm, firmType);
} }
static inline void patchSafeFirm(void) static inline void patch1x2xNativeAndSafeFirm(void)
{ {
u8 *arm9Section = (u8 *)firm + section[2].offset; u8 *arm9Section = (u8 *)firm + section[2].offset;
if(console) if(isN3DS)
{ {
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section, 0); arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C; firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size); 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; for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
u32 loaderOffset = getLoader(arm11Section0, &loaderSize); src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
{
srcModuleSize = *(u32 *)(src + 0x104) * 0x200;
char *moduleName = (char *)(src + 0x200);
memcpy(section[0].address, arm11Section0, loaderOffset); void *module;
memcpy(section[0].address + loaderOffset, injector, injector_size);
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize)); if(memcmp(moduleName, "loader", 6) == 0)
{
module = (void *)injector;
dstModuleSize = injector_size;
}
else
{
module = src;
dstModuleSize = srcModuleSize;
} }
static inline void launchFirm(u32 firmType, u32 bootType) memcpy(dst, module, dstModuleSize);
}
}
static inline void launchFirm(FirmwareType firmType)
{ {
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector //If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
u32 sectionNum; u32 sectionNum;
if(!firmType) if(firmType == NATIVE_FIRM)
{ {
copySection0AndInjectLoader(); copySection0AndInjectSystemModules();
sectionNum = 1; sectionNum = 1;
} }
else sectionNum = 0; else sectionNum = 0;
@@ -369,7 +390,7 @@ static inline void launchFirm(u32 firmType, u32 bootType)
//Determine the ARM11 entry to use //Determine the ARM11 entry to use
vu32 *arm11; vu32 *arm11;
if(bootType) arm11 = (u32 *)0x1FFFFFFC; if(isFirmlaunch) arm11 = (u32 *)0x1FFFFFFC;
else else
{ {
deinitScreens(); deinitScreens();
@@ -379,6 +400,9 @@ static inline void launchFirm(u32 firmType, u32 bootType)
//Set ARM11 kernel entrypoint //Set ARM11 kernel entrypoint
*arm11 = (u32)firm->arm11Entry; *arm11 = (u32)firm->arm11Entry;
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireICache();
//Final jump to ARM9 kernel //Final jump to ARM9 kernel
((void (*)())firm->arm9Entry)(); ((void (*)())firm->arm9Entry)();
} }

View File

@@ -1,14 +1,33 @@
/* /*
* firm.h * 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 #pragma once
#include "types.h" #include "types.h"
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu32 *)0x101401C0) #define PDN_SPI_CNT (*(vu32 *)0x101401C0)
#define CFG_BOOTENV (*(vu32 *)0x10010000)
//FIRM Header layout //FIRM Header layout
typedef struct firmSectionHeader { typedef struct firmSectionHeader {
@@ -28,9 +47,9 @@ typedef struct firmHeader {
firmSectionHeader section[4]; firmSectionHeader section[4];
} firmHeader; } firmHeader;
static inline void loadFirm(u32 firmType, u32 externalFirm); static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource);
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode); static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
static inline void patchLegacyFirm(u32 firmType); static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void); static inline void patch1x2xNativeAndSafeFirm(void);
static inline void copySection0AndInjectLoader(void); static inline void copySection0AndInjectSystemModules(void);
static inline void launchFirm(u32 sectionNum, u32 bootType); static inline void launchFirm(FirmwareType firmType);

View File

@@ -1,10 +1,30 @@
/* /*
* fs.c * 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 "fs.h" #include "fs.h"
#include "memory.h" #include "memory.h"
#include "screeninit.h" #include "strings.h"
#include "cache.h"
#include "screen.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
#include "buttons.h" #include "buttons.h"
#include "../build/loader.h" #include "../build/loader.h"
@@ -12,12 +32,10 @@
static FATFS sdFs, static FATFS sdFs,
nandFs; nandFs;
u32 mountFs(void) void mountFs(void)
{ {
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0; f_mount(&sdFs, "0:", 1);
f_mount(&nandFs, "1:", 0); f_mount(&nandFs, "1:", 0);
return 1;
} }
u32 fileRead(void *dest, const char *path) u32 fileRead(void *dest, const char *path)
@@ -29,6 +47,7 @@ u32 fileRead(void *dest, const char *path)
{ {
unsigned int read; unsigned int read;
size = f_size(&file); size = f_size(&file);
if(dest != NULL)
f_read(&file, dest, size, &read); f_read(&file, dest, size, &read);
f_close(&file); f_close(&file);
} }
@@ -37,16 +56,45 @@ u32 fileRead(void *dest, const char *path)
return size; return size;
} }
void fileWrite(const void *buffer, const char *path, u32 size) u32 getFileSize(const char *path)
{
return fileRead(NULL, path);
}
bool fileWrite(const void *buffer, const char *path, u32 size)
{ {
FIL file; 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; unsigned int written;
f_write(&file, buffer, size, &written); f_write(&file, buffer, size, &written);
f_close(&file); f_close(&file);
return true;
} }
else if(result == FR_NO_PATH)
{
char folder[256];
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 fileDelete(const char *path)
{
f_unlink(path);
} }
void loadPayload(u32 pressed) void loadPayload(u32 pressed)
@@ -76,30 +124,39 @@ void loadPayload(u32 pressed)
{ {
initScreens(); initScreens();
u32 *const loaderAddress = (u32 *)0x24FFFB00; u32 *const loaderAddress = (u32 *)0x24FFFF00;
memcpy(loaderAddress, loader, loader_size); memcpy(loaderAddress, loader, loader_size);
path[14] = '/'; concatenateStrings(path, "/");
memcpy(&path[15], info.altname, 13); concatenateStrings(path, info.altname);
loaderAddress[1] = fileRead((void *)0x24F00000, path); loaderAddress[1] = fileRead((void *)0x24F00000, path);
flushDCacheRange(loaderAddress, loader_size);
flushICacheRange(loaderAddress, loader_size);
((void (*)())loaderAddress)(); ((void (*)())loaderAddress)();
} }
} }
void firmRead(void *dest, const char *firmFolder) u32 firmRead(void *dest, u32 firmType)
{ {
char path[48] = "1:/title/00040138/00000000/content"; const char *firmFolders[4][2] = {{ "00000002", "20000002" },
memcpy(&path[18], firmFolder, 8); { "00000102", "20000102" },
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
char path[48] = "1:/title/00040138/";
concatenateStrings(path, firmFolders[firmType][isN3DS ? 1 : 0]);
concatenateStrings(path, "/content");
DIR dir; DIR dir;
FILINFO info; FILINFO info;
f_opendir(&dir, path); f_opendir(&dir, path);
u32 id = 0xFFFFFFFF; u32 firmVersion = 0xFFFFFFFF;
//Parse the target directory //Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0]) while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
@@ -108,32 +165,26 @@ void firmRead(void *dest, const char *firmFolder)
if(info.altname[9] != 'A') continue; if(info.altname[9] != 'A') continue;
//Convert the .app name to an integer //Convert the .app name to an integer
u32 tempId = 0; u32 tempVersion = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++) for(char *tmp = info.altname; *tmp != '.'; tmp++)
{ {
tempId <<= 4; tempVersion <<= 4;
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0'; tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
} }
//Found an older cxi //Found an older cxi
if(tempId < id) id = tempId; if(tempVersion < firmVersion) firmVersion = tempVersion;
} }
f_closedir(&dir); f_closedir(&dir);
//Complete the string with the .app name //Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14); concatenateStrings(path, "/00000000.app");
//Last digit of the .app
u32 i = 42;
//Convert back the .app name from integer to array //Convert back the .app name from integer to array
while(id) hexItoa(firmVersion, &path[35]);
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[id & 0xF];
id >>= 4;
}
fileRead(dest, path); fileRead(dest, path);
return firmVersion;
} }

View File

@@ -1,5 +1,23 @@
/* /*
* fs.h * 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 #pragma once
@@ -8,8 +26,12 @@
#define PATTERN(a) a "_*.bin" #define PATTERN(a) a "_*.bin"
u32 mountFs(void); extern bool isN3DS;
void mountFs(void);
u32 fileRead(void *dest, const char *path); u32 fileRead(void *dest, const char *path);
void fileWrite(const void *buffer, const char *path, u32 size); u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size);
void fileDelete(const char *path);
void loadPayload(u32 pressed); void loadPayload(u32 pressed);
void firmRead(void *dest, const char *firmFolder); u32 firmRead(void *dest, u32 firmType);

View File

@@ -1,3 +1,25 @@
/*
* 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 "i2c.h" #include "i2c.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@@ -1,3 +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.
*/
/*
* Thanks to the everyone who contributed in the development of this file
*/
#pragma once #pragma once
#include "types.h" #include "types.h"

View File

@@ -1,7 +1,29 @@
/* /*
* memory.c * 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.
*/
/*
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 * Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/ */
#include "memory.h" #include "memory.h"

View File

@@ -1,7 +1,29 @@
/* /*
* memory.h * 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.
*/
/*
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 * Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/ */
#pragma once #pragma once

View File

@@ -1,11 +1,30 @@
/* /*
* patches.c * 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 "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "config.h" #include "config.h"
#include "../build/rebootpatch.h" #include "../build/rebootpatch.h"
#include "../build/svcGetCFWInfopatch.h"
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{ {
@@ -18,6 +37,22 @@ u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200; 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) void patchSignatureChecks(u8 *pos, u32 size)
{ {
const u16 sigPatch[2] = {0x2000, 0x4770}; const u16 sigPatch[2] = {0x2000, 0x4770};
@@ -26,8 +61,8 @@ void patchSignatureChecks(u8 *pos, u32 size)
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4), u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)),
*off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1); *off2 = (u16 *)(memsearch(pos, pattern2, size, sizeof(pattern2)) - 1);
*off = sigPatch[0]; *off = sigPatch[0];
off2[0] = sigPatch[0]; off2[0] = sigPatch[0];
@@ -37,9 +72,9 @@ void patchSignatureChecks(u8 *pos, u32 size)
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
{ {
//Look for firmlaunch code //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 //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); u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
@@ -54,32 +89,28 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
void patchFirmWrites(u8 *pos, u32 size) void patchFirmWrites(u8 *pos, u32 size)
{ {
const u16 writeBlock[2] = {0x2000, 0x46C0};
//Look for FIRM writing code //Look for FIRM writing code
u8 *const off1 = memsearch(pos, "exe:", size, 4); u8 *const off1 = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; 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[0] = 0x2000;
off2[1] = writeBlock[1]; 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 //Look for FIRM writing code
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; 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[0] = 0x2400;
off[1] = writeBlockSafe[1]; off[1] = 0xE01D;
} }
void reimplementSvcBackdoor(u8 *pos, u32 size) void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space)
{ {
//Official implementation of svcBackdoor //Official implementation of svcBackdoor
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
@@ -93,35 +124,51 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1 0x11, 0xFF, 0x2F, 0xE1}; //bx r1
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif if(!arm11SvcTable[0x7B])
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])
{ {
u32 *freeSpace; memcpy(*freeK11Space, svcBackdoor, 40);
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
memcpy(freeSpace, svcBackdoor, 40); arm11SvcTable[0x7B] = 0xFFF00000 + *freeK11Space - pos;
*freeK11Space += 40;
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage);
} }
} }
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) void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02}; 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; if(off != NULL) off[4] = 0xE0;
} }
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console) void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
{ {
const patchData twlPatches[] = { const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0}, {{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
@@ -141,9 +188,9 @@ void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM /* 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) */ if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) : u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6)); (sizeof(agbPatches) / sizeof(patchData) - !CONFIG_SHOWGBABOOT);
const patchData *patches = firmType == 1 ? twlPatches : agbPatches; const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
//Patch //Patch
for(u32 i = 0; i < numPatches; i++) for(u32 i = 0; i < numPatches; i++)
@@ -151,30 +198,13 @@ void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
switch(patches[i].type) switch(patches[i].type)
{ {
case 0: case 0:
memcpy(pos + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]); memcpy(pos + patches[i].offset[isN3DS ? 1 : 0], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break; break;
case 2: case 2:
*(u16 *)(pos + patches[i].offset[console] + 2) = 0; *(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0] + 2) = 0;
case 1: case 1:
*(u16 *)(pos + patches[i].offset[console]) = patches[i].patch.type1; *(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0]) = patches[i].patch.type1;
break; break;
} }
} }
} }
u32 getLoader(u8 *pos, u32 *loaderSize)
{
u8 *off = pos;
u32 size;
while(1)
{
size = *(u32 *)(off + 0x104) * 0x200;
if(*(u32 *)(off + 0x200) == 0x64616F6C) break;
off += size;
}
*loaderSize = size;
return (u32)(off - pos);
}

View File

@@ -1,5 +1,23 @@
/* /*
* patches.h * 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 #pragma once
@@ -15,12 +33,29 @@ typedef struct patchData {
u32 type; u32 type;
} patchData; } 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); 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 patchSignatureChecks(u8 *pos, u32 size);
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size); void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
void patchFirmWrites(u8 *pos, u32 size); void patchFirmWrites(u8 *pos, u32 size);
void patchFirmWriteSafe(u8 *pos, u32 size); void patchOldFirmWrites(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size); void reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space);
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console); void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space);
u32 getLoader(u8 *pos, u32 *loaderSize); void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);

177
source/pin.c Normal file
View File

@@ -0,0 +1,177 @@
/*
* 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.
*/
/*
* pin.c
* Code to manage pin locking for 3ds. By reworks.
*/
#include "draw.h"
#include "config.h"
#include "screen.h"
#include "utils.h"
#include "memory.h"
#include "buttons.h"
#include "fs.h"
#include "pin.h"
#include "crypto.h"
static char pinKeyToLetter(u32 pressed)
{
const char keys[] = "AB--RLUD--XY";
u32 i;
for(i = 31; pressed > 1; i--) pressed /= 2;
return keys[31 - i];
}
void newPin(bool allowSkipping)
{
clearScreens();
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);
//Pad to AES block length with zeroes
u8 __attribute__((aligned(4))) enteredPassword[0x10] = {0};
u8 length = 4 + 2 * (CONFIG_PIN - 1),
cnt = 0;
int charDrawPos = 5 * SPACING_X;
while(cnt < length)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS));
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();
pressed &= PIN_BUTTONS;
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)
{
computePinHash(tmp, enteredPassword);
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
if(!unlock)
{
charDrawPos = 5 * SPACING_X;
cnt = 0;
clearScreens();
drawString("Wrong PIN, try again", 10, 10 + 4 * SPACING_Y, COLOR_RED);
}
}
}
return true;
}

48
source/pin.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
/*
* pin.h
*
* Code to manage pin locking for 3ds. By reworks.
*/
#pragma once
#include "types.h"
#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;
void newPin(bool allowSkipping);
bool verifyPin(void);

259
source/screen.c Normal file
View File

@@ -0,0 +1,259 @@
/*
* 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.
*/
/*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#include "screen.h"
#include "config.h"
#include "memory.h"
#include "cache.h"
#include "draw.h"
#include "i2c.h"
vu32 *const arm11Entry = (vu32 *)0x1FFFFFF8;
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
void __attribute__((naked)) arm11Stub(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Wait for the entry to be set
while(*arm11Entry == ARM11_STUB_ADDRESS);
//Jump to it
((void (*)())*arm11Entry)();
}
static void invokeArm11Function(void (*func)())
{
static bool hasCopiedStub = false;
if(!hasCopiedStub)
{
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
hasCopiedStub = true;
}
*arm11Entry = (u32)func;
while(*arm11Entry);
*arm11Entry = ARM11_STUB_ADDRESS;
}
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Shutdown LCDs
*(vu32 *)0x10202A44 = 0;
*(vu32 *)0x10202244 = 0;
*(vu32 *)0x10202014 = 0;
WAIT_FOR_ARM9();
}
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
}
void updateBrightness(u32 brightnessIndex)
{
static u32 brightnessLevel;
brightnessLevel = brightness[brightnessIndex];
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Change brightness
*(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = brightnessLevel;
WAIT_FOR_ARM9();
}
flushDCacheRange(&brightnessLevel, 4);
invokeArm11Function(ARM11);
}
void clearScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Setting up two simultaneous memory fills using the GPU
vu32 *REGs_PSC0 = (vu32 *)0x10400010;
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
vu32 *REGs_PSC1 = (vu32 *)0x10400020;
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
REGs_PSC1[1] = (u32)(fb->bottom + 0x38400) >> 3; //End address
REGs_PSC1[2] = 0; //Fill value
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
if(fb->top_right != fb->top_left)
{
REGs_PSC0[0] = (u32)fb->top_right >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_right + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
while(!(REGs_PSC0[3] & 2));
}
WAIT_FOR_ARM9();
}
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
}
void initScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
u32 brightnessLevel = brightness[CONFIG_BRIGHTNESS];
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = 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
fb->top_left = (u8 *)0x18300000;
fb->top_right = (u8 *)0x18300000;
fb->bottom = (u8 *)0x18346500;
WAIT_FOR_ARM9();
}
if(PDN_GPU_CNT == 1)
{
flushDCacheRange(&configData, sizeof(cfgData));
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
clearScreens();
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
else
{
clearScreens();
updateBrightness(CONFIG_BRIGHTNESS);
}
}

46
source/screen.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* 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.
*/
/*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#pragma once
#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)();
static volatile struct fb {
u8 *top_left;
u8 *top_right;
u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00;
void deinitScreens(void);
void updateBrightness(u32 brightnessIndex);
void clearScreens(void);
void initScreens(void);

View File

@@ -1,69 +0,0 @@
/*
* screeninit.c
*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#include "screeninit.h"
#include "config.h"
#include "memory.h"
#include "draw.h"
#include "i2c.h"
#include "../build/screeninit.h"
vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Clear ARM11 entry offset
*arm11Entry = 0;
//Shutdown LCDs
*(vu32 *)0x10202A44 = 0;
*(vu32 *)0x10202244 = 0;
*(vu32 *)0x10202014 = 0;
//Wait for the entry to be set
while(!*arm11Entry);
//Jump to it
((void (*)())*arm11Entry)();
}
if(PDN_GPU_CNT != 1)
{
*arm11Entry = (u32)ARM11;
while(*arm11Entry);
}
}
u32 initScreens(void)
{
u32 needToInit = PDN_GPU_CNT == 1;
if(needToInit)
{
u32 *const screenInitAddress = (u32 *)0x24FFFC00;
memcpy(screenInitAddress, screeninit, screeninit_size);
//Write brightness level for the stub to pick up
screenInitAddress[2] = MULTICONFIG(0);
*arm11Entry = (u32)screenInitAddress;
while(*arm11Entry);
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
clearScreens();
return needToInit;
}

View File

@@ -1,15 +0,0 @@
/*
* screeninit.h
*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#pragma once
#include "types.h"
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
void deinitScreens(void);
u32 initScreens(void);

View File

@@ -1,29 +1,70 @@
@ 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.
@ Thanks to the numerous people who took part in writing this file
.section .text.start .section .text.start
.align 4 .align 4
.global _start .global _start
_start: _start:
b start b start
.word 0, 0 .global launchedFirmTidLow
launchedFirmTidLow:
.hword 0, 0, 0, 0, 0, 0, 0, 0
start: start:
@ Change the stack pointer @ Change the stack pointer
mov sp, #0x27000000 mov sp, #0x27000000
@ Disable interrupts
mrs r0, cpsr
orr r0, #0x1C0
msr cpsr_cx, r0
@ Disable caches / MPU
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, #(1<<12) @ - instruction cache disable
bic r0, #(1<<2) @ - data cache disable
bic r0, #(1<<0) @ - mpu disable
mcr p15, 0, r0, c1, c0, 0 @ write control register
@ Flush caches
bl flushEntireDCache
bl flushEntireICache
@ Give read/write access to all the memory regions @ Give read/write access to all the memory regions
ldr r0, =0x33333333 ldr r0, =0x3333333
mcr p15, 0, r0, c5, c0, 2 @ write data access mcr p15, 0, r0, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access mcr p15, 0, r0, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings @ Set MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
ldr r1, =0x01FF801D @ 01ff8000 32k ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
ldr r2, =0x08000027 @ 08000000 1M ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
ldr r3, =0x10000021 @ 10000000 128k ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
ldr r4, =0x10100025 @ 10100000 512k ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
ldr r5, =0x20000035 @ 20000000 128M ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
ldr r6, =0x1FF00027 @ 1FF00000 1M ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
ldr r7, =0x1800002D @ 18000000 8M mov r7, #0
mov r8, #0x15
mcr p15, 0, r0, c6, c0, 0 mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0 mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0 mcr p15, 0, r2, c6, c2, 0
@@ -32,24 +73,18 @@ start:
mcr p15, 0, r5, c6, c5, 0 mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0 mcr p15, 0, r7, c6, c7, 0
mov r0, #0x25 mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 4
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5 mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5 mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
@ Enable caches @ Enable caches / MPU / ITCM
mrc p15, 0, r0, c1, c0, 0 @ read control register mrc p15, 0, r0, c1, c0, 0 @ read control register
orr r0, r0, #(1<<18) @ - ITCM enable
orr r0, r0, #(1<<12) @ - instruction cache enable orr r0, r0, #(1<<12) @ - instruction cache enable
orr r0, r0, #(1<<2) @ - data cache enable orr r0, r0, #(1<<2) @ - data cache enable
orr r0, r0, #(1<<0) @ - mpu enable orr r0, r0, #(1<<0) @ - mpu enable
mcr p15, 0, r0, c1, c0, 0 @ write control register mcr p15, 0, r0, c1, c0, 0 @ write control register
@ Flush caches
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
@ Fix mounting of SDMC @ Fix mounting of SDMC
ldr r0, =0x10000020 ldr r0, =0x10000020
mov r1, #0x340 mov r1, #0x340

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

@@ -1,11 +1,30 @@
/* /*
* types.h * 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 #pragma once
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
//Common data types //Common data types
typedef uint8_t u8; typedef uint8_t u8;
@@ -16,3 +35,20 @@ typedef volatile u8 vu8;
typedef volatile u16 vu16; typedef volatile u16 vu16;
typedef volatile u32 vu32; typedef volatile u32 vu32;
typedef volatile u64 vu64; typedef volatile u64 vu64;
//Used by multiple files
typedef enum FirmwareSource
{
FIRMWARE_SYSNAND = 0,
FIRMWARE_EMUNAND = 1,
FIRMWARE_EMUNAND2 = 2
} FirmwareSource;
typedef enum FirmwareType
{
NATIVE_FIRM = 0,
TWL_FIRM = 1,
AGB_FIRM = 2,
SAFE_FIRM = 3,
NATIVE_FIRM1X2X = 4
} FirmwareType;

View File

@@ -1,10 +1,31 @@
/* /*
* utils.c * 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 "utils.h" #include "utils.h"
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
#include "screen.h"
#include "draw.h"
#include "cache.h"
u32 waitInput(void) u32 waitInput(void)
{ {
@@ -35,8 +56,22 @@ u32 waitInput(void)
void mcuReboot(void) void mcuReboot(void)
{ {
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(1); while(true);
}
void mcuPowerOff(void)
{
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
while(true);
} }
//TODO: add support for TIMER IRQ //TODO: add support for TIMER IRQ
@@ -44,34 +79,46 @@ static inline void startChrono(u64 initialTicks)
{ {
//Based on a NATIVE_FIRM disassembly //Based on a NATIVE_FIRM disassembly
*(vu16 *)0x10003002 = 0; //67MHz REG_TIMER_CNT(0) = 0; //67MHz
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 4; //Count-up for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
for(u32 i = 0; i < 4; i++) *(vu16 *)(0x10003000 + 4 * i) = (u16)(initialTicks >> (16 * i)); for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = (u16)(initialTicks >> (16 * i));
*(vu16 *)0x10003002 = 0x80; //67MHz; enabled REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) = 0x84; //Count-up; enabled for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
}
static inline void stopChrono(void)
{
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
} }
void chrono(u32 seconds) void chrono(u32 seconds)
{ {
static u64 startingTicks = 0; startChrono(0);
if(!startingTicks) startChrono(0); u64 startingTicks = 0;
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
u64 res; u64 res;
do do
{ {
res = 0; res = 0;
for(u32 i = 0; i < 4; i++) res |= *(vu16 *)(0x10003000 + 4 * i) << (16 * i); for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
} }
while(res - startingTicks < seconds * TICKS_PER_SEC); while(res - startingTicks < seconds * TICKS_PER_SEC);
if(!seconds) startingTicks = res; stopChrono();
} }
void stopChrono(void) void error(const char *message)
{ {
for(u32 i = 1; i < 4; i++) *(vu16 *)(0x10003002 + 4 * i) &= ~0x80; initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED);
int posY = drawString(message, 10, 30, COLOR_WHITE);
drawString("Press any button to shutdown", 10, posY + 2 * SPACING_Y, COLOR_WHITE);
waitInput();
mcuPowerOff();
} }

View File

@@ -1,15 +1,37 @@
/* /*
* utils.h * 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 #pragma once
#include "types.h" #include "types.h"
#define TICKS_PER_SEC 67027964ULL
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
extern bool isFirmlaunch;
u32 waitInput(void); u32 waitInput(void);
void mcuReboot(void); void mcuReboot(void);
void mcuPowerOff(void);
#define TICKS_PER_SEC 67027964ULL
void chrono(u32 seconds); void chrono(u32 seconds);
void stopChrono(void); void error(const char *message);