Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5ddc38477 | ||
|
|
8d102256a2 | ||
|
|
2e561f7ea9 | ||
|
|
9656fe1b6f | ||
|
|
48c23f2a43 | ||
|
|
6d82649c3c | ||
|
|
81dea35754 | ||
|
|
fdbe43421b | ||
|
|
0d71560785 | ||
|
|
108e8a0cd4 | ||
|
|
653e81c48e | ||
|
|
0dc0783094 | ||
|
|
13ef1bf6be | ||
|
|
7ea80353f6 | ||
|
|
07bbff7d11 | ||
|
|
2ff4fc3cdd | ||
|
|
c9456055ea | ||
|
|
2900f2d67b | ||
|
|
93c8c90804 | ||
|
|
36e54642d2 | ||
|
|
e04cb28711 | ||
|
|
ad1dc51e06 | ||
|
|
5b6bab7a58 | ||
|
|
9bd2fc659d | ||
|
|
f18633f65f | ||
|
|
1026bc7b4f | ||
|
|
f1dee68142 | ||
|
|
f7cc2d295c | ||
|
|
a6f254b5cf | ||
|
|
00dbbe1b28 | ||
|
|
7f33309903 | ||
|
|
c95808fa2d | ||
|
|
5b6bd048a9 | ||
|
|
28e6ad3372 | ||
|
|
9b128ebba5 | ||
|
|
71f49180c3 | ||
|
|
4a042241a8 | ||
|
|
0eab9127e3 | ||
|
|
9f11991410 | ||
|
|
fec0b95098 | ||
|
|
5081439f53 | ||
|
|
c44aebee4d | ||
|
|
706cd50f25 | ||
|
|
b1b81c87f2 | ||
|
|
bf7e30539e | ||
|
|
5f8a61201b | ||
|
|
ed8aee8b8c | ||
|
|
92ec2af587 | ||
|
|
7960c87579 | ||
|
|
700d572732 | ||
|
|
014a0d86f1 | ||
|
|
88db59405f | ||
|
|
ef2e008700 | ||
|
|
07101c053a | ||
|
|
6c5f6ac475 | ||
|
|
61ecd9a617 | ||
|
|
6f56a9bfe9 | ||
|
|
416875ee46 | ||
|
|
c875b506ea | ||
|
|
ff4517e583 | ||
|
|
92cc989dc9 | ||
|
|
6e5987e3ca | ||
|
|
f03e232b90 | ||
|
|
1eb18c1790 | ||
|
|
3076d56973 | ||
|
|
b35707edf9 | ||
|
|
dfbd0dc9e7 | ||
|
|
620ad7ba71 | ||
|
|
5e4fd53243 | ||
|
|
0ba7630354 | ||
|
|
028d0ec0d5 | ||
|
|
751fa05fcd | ||
|
|
f89845257e | ||
|
|
2f274e2f47 | ||
|
|
38088e80e1 | ||
|
|
14162828ea | ||
|
|
ab8507e09d | ||
|
|
0d25c07333 | ||
|
|
bfc8ba8447 | ||
|
|
a45f8293d9 | ||
|
|
f29b9d14d7 | ||
|
|
9c9fd2deef | ||
|
|
3bb01ffd68 | ||
|
|
bc6d9994dc | ||
|
|
e177f9e0fe | ||
|
|
c5d75d2de9 | ||
|
|
cc0cade4d2 | ||
|
|
1e3362250f | ||
|
|
db16e8d602 | ||
|
|
2a563eddd0 | ||
|
|
6b8474b7b9 | ||
|
|
b5336c81cc | ||
|
|
1fcab825bf | ||
|
|
0306556032 | ||
|
|
b093578046 | ||
|
|
9332b9eb33 | ||
|
|
141c7817a0 | ||
|
|
f155026d8f | ||
|
|
37e467ba60 | ||
|
|
3572b835b5 | ||
|
|
da4f3a72af | ||
|
|
2938bbd11f | ||
|
|
abf3017eb2 | ||
|
|
5c855ea52f | ||
|
|
c83edea7ad | ||
|
|
6d3113c8c3 | ||
|
|
48c48c7bbc | ||
|
|
e4093ed988 | ||
|
|
c79af52720 | ||
|
|
61eeaca6d5 | ||
|
|
320a79ba72 | ||
|
|
2e1b943805 | ||
|
|
bc167dde2d | ||
|
|
7d9a8b4211 |
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
#
|
||||
# THIS IS NOT A SUPPORT FORUM! For support please go to:
|
||||
# Luma3DS GBATemp thread: https://gbatemp.net/threads/luma3ds-noob-proof-3ds-custom-firmware.411110/
|
||||
# /r/3dshacks: http://reddit.com/r/3dshacks/
|
||||
# Nintendo Hacking: https://discordapp.com/invite/C29hYvh
|
||||
# IRC: #3dshacks@rizon
|
||||
#
|
||||
# Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
|
||||
#
|
||||
# For those with GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting
|
||||
#
|
||||
# Please make sure to read "Enable region/language emulation and external .code" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable region/language emulation and external .code" option(s).
|
||||
# Keep in mind that Wiki page only applies to nightly builds. It will NOT WORK with 6.6 Stable Luma3DS.
|
||||
# As of 0.02 (https://github.com/Possum/LumaLocaleSwitcher/releases) LumaLocaleSwitcher's path(s) are for 6.6 Stable and won't work with Luma3DS nightly builds newer or equal to https://github.com/AuroraWright/Luma3DS/commit/b5336c81cc82b6c5e8115249342beb5b065cdce9.
|
||||
# Use this version for Luma3DS nightlies newer or equal to https://github.com/AuroraWright/Luma3DS/commit/b5336c81cc82b6c5e8115249342beb5b065cdce9 :
|
||||
# https://puu.sh/uC5zW/5470adc347.7z (from https://github.com/Possum/LumaLocaleSwitcher/issues/9#issuecomment-285564014)
|
||||
#
|
||||
-->
|
||||
29
Makefile
29
Makefile
@@ -4,12 +4,7 @@ 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
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := Luma3DS
|
||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||
@@ -27,7 +22,7 @@ dir_build := build
|
||||
dir_out := out
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostartfiles
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
@@ -39,8 +34,6 @@ bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/svcG
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $(dir_build)/bundled.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $(dir_build)/bundled.h
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
@@ -61,12 +54,17 @@ clean:
|
||||
@$(MAKE) -C $(dir_haxloader) clean
|
||||
@$(MAKE) -C $(dir_loader) clean
|
||||
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||
@$(MAKE) -C $(dir_arm11_exceptions) clean
|
||||
@$(MAKE) -C $(dir_arm11_exceptions) clean
|
||||
@$(MAKE) -C $(dir_injector) clean
|
||||
@rm -rf $(dir_out) $(dir_build)
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
.PHONY: $(dir_loader)
|
||||
.PHONY: $(dir_arm9_exceptions)
|
||||
.PHONY: $(dir_arm11_exceptions)
|
||||
.PHONY: $(dir_injector)
|
||||
|
||||
$(dir_out) $(dir_build):
|
||||
@mkdir -p "$@"
|
||||
|
||||
@@ -77,7 +75,7 @@ $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
|
||||
@cp -a $(dir_build)/main.bin $@
|
||||
|
||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
@@ -104,11 +102,16 @@ $(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
echo "extern const u8" `(echo $(basename $(notdir $(f))) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $@;\
|
||||
echo "extern const u32" `(echo $(basename $(notdir $(f)))| sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $@;\
|
||||
)
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/bundled.h
|
||||
@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)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
**Luma3DS** is a program to patch the system software of (New) Nintendo 3DS handheld consoles "on the fly", adding features (such as per-game language settings and debugging capabilities for developers) and removing restrictions enforced by Nintendo (such as the region lock).
|
||||
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
|
||||
To use it, you will need a console capable of running homebrew software on the ARM9 processor. We recommend [Plailect's guide](https://github.com/Plailect/Guide/wiki) for details on how to get your system ready.
|
||||
To use it, you will need a console capable of running homebrew software on the ARM9 processor. We recommend [Plailect's guide](https://3ds.guide/) for details on how to get your system ready.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,12 +4,7 @@ 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
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := arm11_exceptions
|
||||
|
||||
@@ -18,7 +13,7 @@ dir_build := build
|
||||
dir_out := ../../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=mpcore -mfpu=vfp
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostdlib
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
@@ -33,7 +28,7 @@ clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
@@ -45,4 +40,3 @@ $(dir_build)/%.o: $(dir_source)/%.c
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
|
||||
//Dump registers
|
||||
//Current order of saved regs: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc, r8-r12, sp, lr, r0-r7
|
||||
u32 cpsr = regs[6];
|
||||
u32 pc = regs[7] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||
u32 pc = regs[7] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 0);
|
||||
|
||||
registerDump[15] = pc;
|
||||
registerDump[16] = cpsr;
|
||||
@@ -106,4 +106,4 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
|
||||
|
||||
cleanInvalidateDCacheAndDMB();
|
||||
mcuReboot(); //Also contains DCache-cleaning code
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,7 @@ 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
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := arm9_exceptions
|
||||
|
||||
@@ -18,7 +13,7 @@ dir_build := build
|
||||
dir_out := ../../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostdlib
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
@@ -33,7 +28,7 @@ clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
@@ -45,4 +40,3 @@ $(dir_build)/%.o: $(dir_source)/%.c
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x01FF7FE0;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
Submodule haxloader/CakeBrah updated: 9f7cea77d4...1efda4e894
Submodule haxloader/CakeHax updated: 5245c7b9dc...329212a8e0
@@ -4,12 +4,7 @@ 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
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
dir_source := source
|
||||
dir_diffs := diffs
|
||||
@@ -20,7 +15,7 @@ dir_build := build
|
||||
dir_out := ../out
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostartfiles
|
||||
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Aurora Wright/TuxSH" --no-print-directory
|
||||
ROPFLAGS := DATNAME=$(name).dat DISPNAME=$(name) GRAPHICS=../graphics/
|
||||
@@ -63,7 +58,7 @@ $(dir_out)/mset/$(name).nds:
|
||||
@mv $(dir_cakesrop)/CakesROP.nds $@
|
||||
|
||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/main.elf: $(objects) ../$(dir_build)/loader.bin.o
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
@@ -77,4 +72,3 @@ $(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
||||
@@ -50,7 +50,7 @@ diff -uNr a/source/brahma.c b/source/brahma.c
|
||||
+ fseek(p , 0, SEEK_END);
|
||||
+ psize = ftell(p);
|
||||
+ if (psize > 5 && psize < 58) {
|
||||
+ char path[psize + 1];
|
||||
+ char path[57];
|
||||
+
|
||||
+ fseek(p, 0, SEEK_SET);
|
||||
+ u32 bytes_read = fread(path, 1, psize, p);
|
||||
@@ -58,7 +58,7 @@ diff -uNr a/source/brahma.c b/source/brahma.c
|
||||
+ if (bytes_read == psize) {
|
||||
+ if (path[psize - 1] == 0xA) psize--;
|
||||
+ if (path[psize - 1] == 0xD) psize--;
|
||||
+ if (psize > 5 && psize < 56 && path[0] == '/' && memcmp(&path[psize - 4], ".bin", 4)) {
|
||||
+ if (psize > 5 && psize < 56 && path[0] == '/' && memcmp(path + psize - 4, ".bin", 4)) {
|
||||
+ path[psize] = 0;
|
||||
+ f = fopen(path, "rb");
|
||||
+ if (f) use_default = false;
|
||||
@@ -103,7 +103,7 @@ diff -uNr a/source/brahma.c b/source/brahma.c
|
||||
diff -uNr a/source/main.c b/source/main.c
|
||||
--- a/source/main.c 2016-09-26 16:05:36.363067000 +0200
|
||||
+++ b/source/main.c 2016-09-26 21:40:35.202513018 +0200
|
||||
@@ -10,7 +10,7 @@
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
int main (void) {
|
||||
if (brahma_init()) {
|
||||
@@ -112,7 +112,7 @@ diff -uNr a/source/main.c b/source/main.c
|
||||
goto error;
|
||||
firm_reboot();
|
||||
brahma_exit();
|
||||
@@ -22,7 +22,7 @@
|
||||
@@ -50,7 +50,7 @@
|
||||
error:
|
||||
gfxInitDefault();
|
||||
consoleInit(GFX_BOTTOM, NULL);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff -uNr a/source/main.c b/source/main.c
|
||||
--- a/source/main.c 2016-09-11 01:04:25.665231884 +0200
|
||||
+++ b/source/main.c 2016-09-14 12:36:28.601439550 +0200
|
||||
@@ -9,6 +9,7 @@
|
||||
#endif
|
||||
@@ -37,6 +37,7 @@
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
+ svcSleepThread(2500 * 1000000ULL);
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x23F00000;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
13
haxloader/source/fatfs/00history.txt
Executable file → Normal file
13
haxloader/source/fatfs/00history.txt
Executable file → Normal file
@@ -212,7 +212,7 @@ R0.10a (January 15, 2014)
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ R0.12a (July 10, 2016)
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Improved f_rename() to be able to rename objects with the same name but case.
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
@@ -277,3 +277,12 @@ R0.12b (September 04, 2016)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
26
haxloader/source/fatfs/00readme.txt
Executable file → Normal file
26
haxloader/source/fatfs/00readme.txt
Executable file → Normal file
@@ -1,21 +1,21 @@
|
||||
FatFs Module Source Files R0.12a
|
||||
FatFs Module Source Files R0.12c
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
history.txt Revision history.
|
||||
ffconf.h Configuration file for FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
ff.c FatFs module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external functions.
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external modules.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module that written
|
||||
to control the target storage device.
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
||||
|
||||
737
haxloader/source/fatfs/ff.c
Executable file → Normal file
737
haxloader/source/fatfs/ff.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
25
haxloader/source/fatfs/ff.h
Executable file → Normal file
25
haxloader/source/fatfs/ff.h
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12b /
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||
/ Copyright (C) 2017, 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
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 68020 /* Revision ID */
|
||||
#define _FATFS 68300 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -42,13 +42,6 @@ typedef struct {
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -140,14 +133,15 @@ typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
@@ -163,7 +157,7 @@ typedef struct {
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
@@ -185,7 +179,7 @@ typedef struct {
|
||||
_FDID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if _USE_LFN != 0
|
||||
@@ -285,6 +279,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
|
||||
23
haxloader/source/fatfs/ffconf.h
Executable file → Normal file
23
haxloader/source/fatfs/ffconf.h
Executable file → Normal file
@@ -2,7 +2,7 @@
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 68020 /* Revision ID */
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@@ -73,7 +73,7 @@
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
@@ -148,7 +148,7 @@
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
@@ -172,11 +172,11 @@
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
@@ -204,7 +204,7 @@
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
@@ -212,20 +212,20 @@
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards C89 compatibility. */
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2016
|
||||
#define _NORTC_YEAR 2017
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
|
||||
@@ -258,10 +258,11 @@
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
2
haxloader/source/fatfs/integer.h
Executable file → Normal file
2
haxloader/source/fatfs/integer.h
Executable file → Normal file
@@ -30,7 +30,7 @@ typedef unsigned short WCHAR;
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
/* This type MUST be 64-bit (Remove this for C89 compatibility) */
|
||||
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
|
||||
typedef unsigned long long QWORD;
|
||||
|
||||
#endif
|
||||
|
||||
0
haxloader/source/fatfs/option/ccsbcs.c
Executable file → Normal file
0
haxloader/source/fatfs/option/ccsbcs.c
Executable file → Normal file
@@ -43,13 +43,13 @@ void main(void)
|
||||
|
||||
if(pathSize > 5 && pathSize < 58)
|
||||
{
|
||||
char path[pathSize + 1];
|
||||
char path[57];
|
||||
unsigned int read;
|
||||
f_read(&pathFile, path, pathSize, &read);
|
||||
if(path[pathSize - 1] == 0xA) pathSize--;
|
||||
if(path[pathSize - 1] == 0xD) pathSize--;
|
||||
|
||||
if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0)
|
||||
if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(path + pathSize - 4, ".bin", 4) == 0)
|
||||
{
|
||||
path[pathSize] = 0;
|
||||
foundPayload = f_open(&payload, path, FA_READ) == FR_OK;
|
||||
@@ -63,7 +63,7 @@ void main(void)
|
||||
|
||||
if(foundPayload)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x24FFFF00;
|
||||
u32 *loaderAddress = (u32 *)0x24FFFE00;
|
||||
void *payloadAddress = (void *)0x24F00000;
|
||||
u32 payloadSize = f_size(&payload);
|
||||
|
||||
|
||||
@@ -6,14 +6,10 @@ 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_patches := patches
|
||||
dir_build := build
|
||||
dir_out := ../$(dir_build)
|
||||
|
||||
@@ -23,14 +19,19 @@ LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
|
||||
|
||||
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
|
||||
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
|
||||
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ASFLAGS)
|
||||
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
|
||||
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math $(INCLUDE) -DARM11 -D_3DS
|
||||
LDFLAGS := -specs=3dsx.specs $(ASFLAGS) -Wl,--section-start,.text=0x14000000
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c))
|
||||
|
||||
bundled = $(dir_build)/romfsredir.bin.o
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).bin
|
||||
|
||||
@@ -38,19 +39,35 @@ all: $(dir_out)/$(name).bin
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
$(dir_build):
|
||||
@mkdir -p "$@"
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(dir_build)/$(name).elf: $(bundled) $(objects)
|
||||
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
$(dir_build)/%.bin: $(dir_patches)/%.s $(dir_build)
|
||||
@armips $<
|
||||
|
||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
echo "extern const u8" `(echo $(basename $(notdir $(f))) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $@;\
|
||||
echo "extern const u32" `(echo $(basename $(notdir $(f)))| sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $@;\
|
||||
)
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/bundled.h
|
||||
@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)
|
||||
|
||||
99
injector/patches/romfsredir.s
Normal file
99
injector/patches/romfsredir.s
Normal file
@@ -0,0 +1,99 @@
|
||||
.arm.little
|
||||
.create "build/romfsredir.bin", 0
|
||||
|
||||
.macro addr, reg, func
|
||||
add reg, pc, #func-.-8
|
||||
.endmacro
|
||||
.macro load, reg, func
|
||||
ldr reg, [pc, #func-.-8]
|
||||
.endmacro
|
||||
|
||||
; Patch by delebile
|
||||
|
||||
.arm
|
||||
_start:
|
||||
|
||||
; Jumps here before the fsOpenFileDirectly call
|
||||
_mountArchive:
|
||||
b mountArchive
|
||||
.word 0xdead0000 ; Substituted opcode
|
||||
.word 0xdead0001 ; Branch to hooked function
|
||||
|
||||
; Jumps here before every iFileOpen call
|
||||
_fsRedir:
|
||||
b fsRedir
|
||||
.word 0xdead0002 ; Substituted opcode
|
||||
.word 0xdead0003 ; Branch to hooked function
|
||||
|
||||
; Mounts the archive and registers it as 'lf:'
|
||||
mountArchive:
|
||||
cmp r3, #3
|
||||
bne _mountArchive + 4
|
||||
stmfd sp!, {r0-r4, lr}
|
||||
sub sp, sp, #4
|
||||
load r1, archiveId
|
||||
mov r0, sp
|
||||
load r4, fsMountArchive
|
||||
blx r4
|
||||
mov r3, #0
|
||||
mov r2, #0
|
||||
ldr r1, [sp]
|
||||
addr r0, archiveName
|
||||
load r4, fsRegisterArchive
|
||||
blx r4
|
||||
add sp, sp, #4
|
||||
ldmfd sp!, {r0-r4, lr}
|
||||
b _mountArchive + 4
|
||||
|
||||
; Check the path passed to iFileOpen.
|
||||
; If it is trying to access a RomFS file, we try to
|
||||
; open it from the LayeredFS folder.
|
||||
; If the file cannot be opened, we just open
|
||||
; it from its original archive like nothing happened
|
||||
fsRedir:
|
||||
stmfd sp!, {r0-r12, lr}
|
||||
ldrb r12, [r1]
|
||||
cmp r12, #0x72 ; 'r', should include "rom:" and "rom2:"
|
||||
cmpne r12, #0x70 ; 'p', should include "patch:"
|
||||
bne endRedir
|
||||
sub sp, sp, #0x400
|
||||
pathRedir:
|
||||
stmfd sp!, {r0-r3}
|
||||
add r0, sp, #0x10
|
||||
addr r3, customPath
|
||||
pathRedir_1:
|
||||
ldrb r2, [r3], #1
|
||||
strh r2, [r0], #2
|
||||
cmp r2, #0
|
||||
bne pathRedir_1
|
||||
sub r0, r0, #2
|
||||
pathRedir_2:
|
||||
ldrh r2, [r1], #2
|
||||
cmp r2, #0x3A ; ':'
|
||||
bne pathRedir_2
|
||||
pathRedir_3:
|
||||
ldrh r2, [r1], #2
|
||||
strh r2, [r0], #2
|
||||
cmp r2, #0
|
||||
bne pathRedir_3
|
||||
ldmfd sp!, {r0-r3}
|
||||
mov r1, sp
|
||||
bl _fsRedir + 4
|
||||
add sp, sp, #0x400
|
||||
cmp r0, #0
|
||||
|
||||
endRedir:
|
||||
ldmfd sp!, {r0-r12, lr}
|
||||
moveq r0, #0
|
||||
bxeq lr
|
||||
b _fsRedir + 4
|
||||
|
||||
.pool
|
||||
.align 4
|
||||
archiveName : .dcb "lf:", 0
|
||||
fsMountArchive : .word 0xdead0005
|
||||
fsRegisterArchive : .word 0xdead0006
|
||||
archiveId : .word 0xdead0007
|
||||
customPath : .word 0xdead0004
|
||||
|
||||
.close
|
||||
@@ -107,3 +107,75 @@ Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archi
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path)
|
||||
{
|
||||
if(!archive) return -2;
|
||||
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x80C,3,2); // 0x80C00C2
|
||||
cmdbuf[1] = id;
|
||||
cmdbuf[2] = path.type;
|
||||
cmdbuf[3] = path.size;
|
||||
cmdbuf[4] = IPC_Desc_StaticBuffer(path.size, 0);
|
||||
cmdbuf[5] = (u32) path.data;
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
|
||||
|
||||
if(archive) *archive = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result FSLDR_CloseArchive(FS_Archive archive)
|
||||
{
|
||||
if(!archive) return -2;
|
||||
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x80E,2,0); // 0x80E0080
|
||||
cmdbuf[1] = (u32) archive;
|
||||
cmdbuf[2] = (u32) (archive >> 32);
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x80B,4,2); // 0x80B0102
|
||||
cmdbuf[1] = (u32) archive;
|
||||
cmdbuf[2] = (u32) (archive >> 32);
|
||||
cmdbuf[3] = path.type;
|
||||
cmdbuf[4] = path.size;
|
||||
cmdbuf[5] = IPC_Desc_StaticBuffer(path.size, 0);
|
||||
cmdbuf[6] = (u32) path.data;
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
|
||||
|
||||
if(out) *out = cmdbuf[3];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result FSDIRLDR_Close(Handle handle)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x802,0,0); // 0x8020000
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
|
||||
|
||||
ret = cmdbuf[1];
|
||||
if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -7,3 +7,7 @@ void fsldrExit(void);
|
||||
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version);
|
||||
Result FSLDR_SetPriority(u32 priority);
|
||||
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes);
|
||||
Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path);
|
||||
Result FSLDR_CloseArchive(FS_Archive archive);
|
||||
Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path);
|
||||
Result FSDIRLDR_Close(Handle handle);
|
||||
@@ -158,7 +158,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
|
||||
u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8);
|
||||
|
||||
// patch
|
||||
patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12);
|
||||
patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12, g_exheader.codesetinfo.text.codesize, g_exheader.codesetinfo.ro.codesize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,9 @@
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
|
||||
#define CONFIG(a) (((info.config >> (a + 20)) & 1) != 0)
|
||||
#define MULTICONFIG(a) ((info.config >> (a * 2 + 8)) & 3)
|
||||
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||
@@ -18,8 +21,7 @@ enum multiOptions
|
||||
BRIGHTNESS,
|
||||
SPLASH,
|
||||
PIN,
|
||||
NEWCPU,
|
||||
DEVOPTIONS
|
||||
NEWCPU
|
||||
};
|
||||
|
||||
enum singleOptions
|
||||
@@ -28,10 +30,12 @@ enum singleOptions
|
||||
USESYSFIRM,
|
||||
LOADEXTFIRMSANDMODULES,
|
||||
USECUSTOMPATH,
|
||||
USELANGEMUANDCODE,
|
||||
PATCHGAMES,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHACCESS
|
||||
PATCHACCESS,
|
||||
PATCHUNITINFO,
|
||||
ENABLEEXCEPTIONHANDLERS
|
||||
};
|
||||
|
||||
enum flags
|
||||
@@ -40,4 +44,4 @@ enum flags
|
||||
ISSAFEMODE
|
||||
};
|
||||
|
||||
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size);
|
||||
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize);
|
||||
|
||||
14
linker.ld
14
linker.ld
@@ -1,11 +1,15 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x23F00000;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,7 @@ 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
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := $(shell basename $(CURDIR))
|
||||
|
||||
@@ -18,7 +13,7 @@ dir_build := build
|
||||
dir_out := ../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostdlib
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
@@ -33,7 +28,7 @@ clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
@@ -47,4 +42,3 @@ $(dir_build)/%.o: $(dir_source)/%.c
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x24FFFE00;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,12 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
||||
.arm
|
||||
; Interesting registers and locations to keep in mind, set just before this code is ran:
|
||||
; - r1: FIRM path in exefs.
|
||||
; - r7: pointer to file object
|
||||
; - r7 (or r8): pointer to file object
|
||||
; - *r7: vtable
|
||||
; - *(vtable + 0x28): fread function
|
||||
; - *(r7 + 8): file handle
|
||||
|
||||
sub r7, r0, #8
|
||||
mov r8, r1
|
||||
|
||||
pxi_wait_recv:
|
||||
@@ -105,6 +106,8 @@ nand_mount: .dcw "nand"
|
||||
.align 4
|
||||
kernelcode_start:
|
||||
|
||||
ldr sp, =0x080FF000
|
||||
|
||||
; Disable MPU
|
||||
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
@@ -136,4 +139,5 @@ nand_mount: .dcw "nand"
|
||||
bx r0
|
||||
|
||||
.pool
|
||||
.close
|
||||
.close
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
#define BUTTON_UP (1 << 6)
|
||||
#define BUTTON_DOWN (1 << 7)
|
||||
|
||||
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
|
||||
#define EMUNAND_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||
#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)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
||||
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
|
||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT)
|
||||
182
source/config.c
182
source/config.c
@@ -30,6 +30,8 @@
|
||||
#include "pin.h"
|
||||
|
||||
CfgData configData;
|
||||
ConfigurationStatus needConfig;
|
||||
static u32 oldConfig;
|
||||
|
||||
bool readConfig(void)
|
||||
{
|
||||
@@ -41,32 +43,33 @@ bool readConfig(void)
|
||||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
||||
{
|
||||
configData.config = 0;
|
||||
|
||||
ret = false;
|
||||
}
|
||||
else ret = true;
|
||||
|
||||
oldConfig = configData.config;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
|
||||
void writeConfig(bool isPayloadLaunch)
|
||||
{
|
||||
if(isPayloadLaunch) configData.config = (configData.config & 0xFFFFFF00) | (oldConfig & 0xFF);
|
||||
|
||||
/* If the configuration is different from previously, overwrite it.
|
||||
Just the no-forcing flag being set is not enough */
|
||||
if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFF7F) != configData.config)
|
||||
if(needConfig != CREATE_CONFIGURATION && (configData.config & 0xFFFFFF7F) == oldConfig) return;
|
||||
|
||||
if(needConfig == CREATE_CONFIGURATION)
|
||||
{
|
||||
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 & 0xFFFFFF00) | (configTemp & 0xFF);
|
||||
|
||||
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
||||
error("Error writing the configuration file");
|
||||
memcpy(configData.magic, "CONF", 4);
|
||||
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
|
||||
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
|
||||
}
|
||||
|
||||
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
||||
error("Error writing the configuration file");
|
||||
}
|
||||
|
||||
void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
@@ -76,17 +79,18 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
"Splash: Off( ) Before( ) After( ) payloads",
|
||||
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
||||
"Dev. features: Off( ) ErrDisp( ) UNITINFO( )"
|
||||
};
|
||||
|
||||
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
||||
"( ) Use SysNAND FIRM if booting with R",
|
||||
"( ) Enable loading external FIRMs and modules",
|
||||
"( ) Use custom path",
|
||||
"( ) Enable region/language emu. and ext. .code",
|
||||
"( ) Enable game patching",
|
||||
"( ) Show NAND or user string in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
"( ) Patch SVC/service/archive/ARM9 access"
|
||||
"( ) Patch SVC/service/archive/ARM9 access",
|
||||
"( ) Set developer UNITINFO",
|
||||
"( ) Enable exception handlers"
|
||||
};
|
||||
|
||||
const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||
@@ -118,19 +122,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
"'Clock+L2' can cause issues with some\n"
|
||||
"games.",
|
||||
|
||||
"Select the developer features.\n\n"
|
||||
"\t* 'Off' disables exception handlers\n"
|
||||
"in FIRM.\n"
|
||||
"\t* 'ErrDisp' displays debug info\n"
|
||||
"on the 'An error has occurred' screen.\n"
|
||||
"\t* 'UNITINFO' makes the console be\n"
|
||||
"always detected as a development unit\n"
|
||||
"(which breaks online features and\n"
|
||||
"allows booting some developer\n"
|
||||
"software and installing dev CIAs).\n\n"
|
||||
"Only change this if you know what you\n"
|
||||
"are doing!",
|
||||
|
||||
"If enabled, SysNAND will be launched\n"
|
||||
"on boot.\n\n"
|
||||
"Otherwise, an EmuNAND will.\n\n"
|
||||
@@ -162,10 +153,13 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
|
||||
"Enable overriding the region and\n"
|
||||
"language configuration and the usage\n"
|
||||
"of patched code binaries for specific\n"
|
||||
"games.\n\n"
|
||||
"Also makes certain DLCs for\n"
|
||||
"out-of-region games work.\n\n"
|
||||
"of patched code binaries,\n"
|
||||
"IPS code patches and LayeredFS\n"
|
||||
"for specific games.\n\n"
|
||||
"Also makes certain DLCs\n"
|
||||
"for out-of-region games work.\n\n"
|
||||
"Enabling this requires the\n"
|
||||
"archive patch to be applied.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable showing the current NAND/FIRM:\n\n"
|
||||
@@ -188,8 +182,22 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
"The service and archive patches\n"
|
||||
"don't work on New 3DS FIRMs between\n"
|
||||
"9.3 and 10.4.\n\n"
|
||||
"Only change this if you know what you\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
|
||||
"Make the console be always detected\n"
|
||||
"as a development unit, and conversely.\n"
|
||||
"(which breaks online features, amiibo\n"
|
||||
"and retail CIAs, but allows installing\n"
|
||||
"and booting some developer software).\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
|
||||
"Enable Luma3DS's ARM9/ARM11 exception\n"
|
||||
"handlers.\n"
|
||||
"A9LH is required, and Luma3DS should\n"
|
||||
"be ran as arm9loaderhax.bin.\n"
|
||||
"Useful for debugging."
|
||||
};
|
||||
|
||||
struct multiOption {
|
||||
@@ -203,7 +211,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
{ .posXs = {12, 22, 31, 0}, .visible = true },
|
||||
{ .posXs = {14, 19, 24, 29}, .visible = true },
|
||||
{ .posXs = {17, 26, 32, 44}, .visible = ISN3DS },
|
||||
{ .posXs = {19, 30, 42, 0}, .visible = true }
|
||||
};
|
||||
|
||||
struct singleOption {
|
||||
@@ -218,14 +225,18 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true }
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true}
|
||||
};
|
||||
|
||||
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
|
||||
singleOptionsAmount = sizeof(singleOptions) / sizeof(struct singleOption),
|
||||
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
|
||||
selectedOption;
|
||||
selectedOption,
|
||||
singleSelected;
|
||||
bool isMultiOption = false;
|
||||
|
||||
//Parse the existing options
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
@@ -236,22 +247,21 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
initScreens();
|
||||
|
||||
drawString(CONFIG_TITLE, true, 10, 10, COLOR_TITLE);
|
||||
drawString("Press A to select, START to save", true, 10, 30, COLOR_WHITE);
|
||||
drawString("Press A to select, START to save", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||
|
||||
//Character to display a selected option
|
||||
char selected = 'x';
|
||||
|
||||
u32 endPos = 42;
|
||||
u32 endPos = 10 + 2 * SPACING_Y;
|
||||
|
||||
//Display all the multiple choice options in white
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
{
|
||||
if(multiOptions[i].visible)
|
||||
{
|
||||
multiOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE);
|
||||
drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
||||
}
|
||||
if(!multiOptions[i].visible) continue;
|
||||
|
||||
multiOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE);
|
||||
drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
||||
}
|
||||
|
||||
endPos += SPACING_Y / 2;
|
||||
@@ -259,33 +269,34 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
//Display all the normal options in white except for the first one
|
||||
for(u32 i = 0, color = COLOR_RED; i < singleOptionsAmount; i++)
|
||||
{
|
||||
if(singleOptions[i].visible)
|
||||
{
|
||||
singleOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color);
|
||||
if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color);
|
||||
if(!singleOptions[i].visible) continue;
|
||||
|
||||
if(color == COLOR_RED)
|
||||
{
|
||||
selectedOption = i + multiOptionsAmount;
|
||||
color = COLOR_WHITE;
|
||||
}
|
||||
singleOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color);
|
||||
if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color);
|
||||
|
||||
if(color == COLOR_RED)
|
||||
{
|
||||
singleSelected = i;
|
||||
selectedOption = i + multiOptionsAmount;
|
||||
color = COLOR_WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
||||
|
||||
u32 pressed = 0;
|
||||
|
||||
//Boring configuration menu
|
||||
while(pressed != BUTTON_START)
|
||||
while(true)
|
||||
{
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
pressed = waitInput(true);
|
||||
}
|
||||
while(!(pressed & MENU_BUTTONS));
|
||||
|
||||
if(pressed == BUTTON_START) break;
|
||||
|
||||
if(pressed != BUTTON_A)
|
||||
{
|
||||
//Remember the previously selected option
|
||||
@@ -309,13 +320,26 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
pressed = BUTTON_UP;
|
||||
selectedOption = totalIndexes;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(selectedOption < multiOptionsAmount)
|
||||
{
|
||||
if(multiOptions[selectedOption].visible) break;
|
||||
if(!multiOptions[selectedOption].visible) continue;
|
||||
|
||||
isMultiOption = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
singleSelected = selectedOption - multiOptionsAmount;
|
||||
|
||||
if(!singleOptions[singleSelected].visible) continue;
|
||||
|
||||
isMultiOption = false;
|
||||
break;
|
||||
}
|
||||
else if(singleOptions[selectedOption - multiOptionsAmount].visible) break;
|
||||
}
|
||||
|
||||
if(selectedOption == oldSelectedOption) continue;
|
||||
@@ -333,21 +357,16 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
||||
}
|
||||
|
||||
if(selectedOption < multiOptionsAmount)
|
||||
drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED);
|
||||
else
|
||||
{
|
||||
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||
drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
|
||||
}
|
||||
if(isMultiOption) drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED);
|
||||
else drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
|
||||
|
||||
clearScreens(false, true, false);
|
||||
drawString(optionsDescription[oldSelectedOption], false, 10, 10, COLOR_BLACK);
|
||||
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//The selected option's status changed, print the 'x's accordingly
|
||||
if(selectedOption < multiOptionsAmount)
|
||||
if(isMultiOption)
|
||||
{
|
||||
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
||||
drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
||||
@@ -357,20 +376,15 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
}
|
||||
else
|
||||
{
|
||||
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
||||
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
||||
if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
||||
bool oldEnabled = singleOptions[singleSelected].enabled;
|
||||
singleOptions[singleSelected].enabled = !oldEnabled;
|
||||
if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
|
||||
if(selectedOption < multiOptionsAmount)
|
||||
drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
||||
else
|
||||
{
|
||||
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||
if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
||||
}
|
||||
if(isMultiOption) drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
||||
else if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
||||
}
|
||||
|
||||
//Preserve the last-used boot options (first 9 bits)
|
||||
@@ -387,8 +401,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
||||
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
|
||||
else if(oldPinStatus) fileDelete(PIN_FILE);
|
||||
|
||||
//Wait for the pressed buttons to change
|
||||
while(HID_PAD & PIN_BUTTONS);
|
||||
|
||||
chrono(2);
|
||||
}
|
||||
wait(2000ULL);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#define CONFIG_FILE "config.bin"
|
||||
#define CONFIG_VERSIONMAJOR 1
|
||||
#define CONFIG_VERSIONMINOR 7
|
||||
#define CONFIG_VERSIONMINOR 9
|
||||
|
||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||
@@ -44,7 +44,6 @@ enum multiOptions
|
||||
SPLASH,
|
||||
PIN,
|
||||
NEWCPU,
|
||||
DEVOPTIONS
|
||||
};
|
||||
|
||||
enum singleOptions
|
||||
@@ -53,10 +52,12 @@ enum singleOptions
|
||||
USESYSFIRM,
|
||||
LOADEXTFIRMSANDMODULES,
|
||||
USECUSTOMPATH,
|
||||
USELANGEMUANDCODE,
|
||||
PATCHGAMES,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHACCESS
|
||||
PATCHACCESS,
|
||||
PATCHUNITINFO,
|
||||
ENABLEEXCEPTIONHANDLERS
|
||||
};
|
||||
|
||||
typedef enum ConfigurationStatus
|
||||
@@ -67,5 +68,5 @@ typedef enum ConfigurationStatus
|
||||
} ConfigurationStatus;
|
||||
|
||||
bool readConfig(void);
|
||||
void writeConfig(ConfigurationStatus needConfig, u32 configTemp);
|
||||
void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode);
|
||||
void writeConfig(bool isPayloadLaunch);
|
||||
void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode);
|
||||
|
||||
220
source/crypto.c
220
source/crypto.c
@@ -85,15 +85,36 @@ __asm__\
|
||||
|
||||
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
|
||||
{
|
||||
if(keyslot <= 0x03) return; //Ignore TWL keys for now
|
||||
u32 *key32 = (u32 *)key;
|
||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||
|
||||
REG_AESKEYFIFO[keyType] = key32[0];
|
||||
REG_AESKEYFIFO[keyType] = key32[1];
|
||||
REG_AESKEYFIFO[keyType] = key32[2];
|
||||
REG_AESKEYFIFO[keyType] = key32[3];
|
||||
if(keyslot <= 3)
|
||||
{
|
||||
if((mode & AES_CNT_INPUT_ORDER) == AES_INPUT_REVERSED)
|
||||
{
|
||||
REGs_AESTWLKEYS[keyslot][keyType][0] = key32[3];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][1] = key32[2];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][2] = key32[1];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][3] = key32[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
REGs_AESTWLKEYS[keyslot][keyType][0] = key32[0];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][1] = key32[1];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][2] = key32[2];
|
||||
REGs_AESTWLKEYS[keyslot][keyType][3] = key32[3];
|
||||
}
|
||||
}
|
||||
|
||||
else if(keyslot < 0x40)
|
||||
{
|
||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||
|
||||
REG_AESKEYFIFO[keyType] = key32[0];
|
||||
REG_AESKEYFIFO[keyType] = key32[1];
|
||||
REG_AESKEYFIFO[keyType] = key32[2];
|
||||
REG_AESKEYFIFO[keyType] = key32[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void aes_use_keyslot(u8 keyslot)
|
||||
@@ -299,11 +320,9 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
__attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE],
|
||||
shaHashBackup[SHA_256_HASH_SIZE];
|
||||
__attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE];
|
||||
static u8 nandSlot;
|
||||
static u32 fatStart;
|
||||
static bool didShaHashBackup = false;
|
||||
|
||||
FirmwareSource firmSource;
|
||||
|
||||
@@ -395,7 +414,7 @@ void set6x7xKeys(void)
|
||||
aes_setkey(0x25, keyX0x25s[ISDEVUNIT ? 1 : 0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x2F, keyY0x2Fs[ISDEVUNIT ? 1 : 0], 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,
|
||||
/* [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);
|
||||
@@ -403,57 +422,62 @@ void set6x7xKeys(void)
|
||||
|
||||
bool decryptExeFs(Cxi *cxi)
|
||||
{
|
||||
bool isCxi;
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false;
|
||||
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0)
|
||||
{
|
||||
isCxi = true;
|
||||
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
||||
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
||||
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
||||
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
||||
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
ncchCtr[7 - i] = cxi->ncch.partitionId[i];
|
||||
ncchCtr[8] = 2;
|
||||
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
ncchCtr[7 - i] = cxi->ncch.partitionId[i];
|
||||
ncchCtr[8] = 2;
|
||||
aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x2C);
|
||||
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x2C);
|
||||
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
else isCxi = false;
|
||||
|
||||
return isCxi && memcmp(cxi, "FIRM", 4) == 0;
|
||||
return memcmp(cxi, "FIRM", 4) == 0;
|
||||
}
|
||||
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
||||
{
|
||||
bool isTicket;
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false;
|
||||
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) == 0)
|
||||
{
|
||||
isTicket = true;
|
||||
__attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
|
||||
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
|
||||
cetkIv[AES_BLOCK_SIZE] = {0};
|
||||
memcpy(titleKey, ticket->titleKey, sizeof(titleKey));
|
||||
memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId));
|
||||
|
||||
__attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
|
||||
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
|
||||
cetkIv[AES_BLOCK_SIZE] = {0};
|
||||
memcpy(titleKey, ticket->titleKey, sizeof(titleKey));
|
||||
memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId));
|
||||
aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x3D);
|
||||
aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x3D);
|
||||
aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
__attribute__((aligned(4))) u8 ncchIv[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
__attribute__((aligned(4))) u8 ncchIv[AES_BLOCK_SIZE] = {0};
|
||||
aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x16);
|
||||
aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x16);
|
||||
aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
else isTicket = false;
|
||||
return decryptExeFs(cxi);
|
||||
}
|
||||
|
||||
return isTicket && decryptExeFs(cxi);
|
||||
static inline void twlConsoleInfoInit(void)
|
||||
{
|
||||
u64 twlConsoleId = CFG_UNITINFO != 0 ? OTP_DEVCONSOLEID : (0x80000000ULL | (*(vu64 *)0x01FFB808 ^ 0x8C267B7B358A6AFULL));
|
||||
CFG_TWLUNITINFO = CFG_UNITINFO;
|
||||
OTP_TWLCONSOLEID = twlConsoleId;
|
||||
|
||||
*REG_AESCNT = 0;
|
||||
|
||||
vu32 *k3X = REGs_AESTWLKEYS[3][1], *k1X = REGs_AESTWLKEYS[1][1];
|
||||
|
||||
k3X[0] = (u32)twlConsoleId;
|
||||
k3X[3] = (u32)(twlConsoleId >> 32);
|
||||
|
||||
k1X[2] = (u32)(twlConsoleId >> 32);
|
||||
k1X[3] = (u32)twlConsoleId;
|
||||
}
|
||||
|
||||
void kernel9Loader(Arm9Bin *arm9Section)
|
||||
@@ -476,36 +500,27 @@ void kernel9Loader(Arm9Bin *arm9Section)
|
||||
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
|
||||
bool needToDecrypt = *startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000;
|
||||
|
||||
if(k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))
|
||||
{
|
||||
//Set 0x11 keyslot
|
||||
__attribute__((aligned(4))) const u8 key1s[2][AES_BLOCK_SIZE] = {
|
||||
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
|
||||
{0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}
|
||||
},
|
||||
key2s[2][AES_BLOCK_SIZE] = {
|
||||
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
|
||||
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}
|
||||
};
|
||||
//Set 0x11 keyslot
|
||||
__attribute__((aligned(4))) const u8 key1s[2][AES_BLOCK_SIZE] = {
|
||||
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
|
||||
{0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}
|
||||
},
|
||||
key2s[2][AES_BLOCK_SIZE] = {
|
||||
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
|
||||
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}
|
||||
};
|
||||
|
||||
aes_setkey(0x11, k9lVersion == 2 ? key2s[ISDEVUNIT ? 1 : 0] : key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
aes_setkey(0x11, k9lVersion == 2 ? key2s[ISDEVUNIT ? 1 : 0] : key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
if(needToDecrypt)
|
||||
{
|
||||
u8 arm9BinSlot;
|
||||
u8 arm9BinSlot = k9lVersion == 0 ? 0x15 : 0x16;
|
||||
|
||||
if(!k9lVersion) arm9BinSlot = 0x15;
|
||||
else
|
||||
{
|
||||
arm9BinSlot = 0x16;
|
||||
|
||||
//Set keyX
|
||||
__attribute__((aligned(4))) u8 keyX[AES_BLOCK_SIZE];
|
||||
aes_use_keyslot(0x11);
|
||||
aes(keyX, arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(0x16, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
//Set keyX
|
||||
__attribute__((aligned(4))) u8 keyX[AES_BLOCK_SIZE];
|
||||
aes_use_keyslot(0x11);
|
||||
aes(keyX, k9lVersion == 0 ? arm9Section->keyX : arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Set keyY
|
||||
__attribute__((aligned(4))) u8 keyY[AES_BLOCK_SIZE];
|
||||
@@ -523,19 +538,42 @@ void kernel9Loader(Arm9Bin *arm9Section)
|
||||
if(*startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000) error("Failed to decrypt the ARM9 binary.");
|
||||
}
|
||||
|
||||
//Set >=9.6 KeyXs
|
||||
__attribute__((aligned(4))) u8 keyBlocks[2][AES_BLOCK_SIZE] = {
|
||||
{0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF, 0x4D, 0xCA, 0x76, 0xDF},
|
||||
{0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}
|
||||
}, decKey[AES_BLOCK_SIZE];
|
||||
|
||||
u8 firstKey;
|
||||
u32 keyBlocksIndex;
|
||||
|
||||
if(k9lVersion == 2)
|
||||
{
|
||||
__attribute__((aligned(4))) u8 keyData[AES_BLOCK_SIZE] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
|
||||
decKey[sizeof(keyData)];
|
||||
firstKey = 0x19;
|
||||
keyBlocksIndex = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
firstKey = 0x18;
|
||||
keyBlocksIndex = 0;
|
||||
}
|
||||
|
||||
//Set keys 0x19..0x1F keyXs
|
||||
aes_use_keyslot(0x11);
|
||||
for(u8 slot = firstKey; slot < 0x20; slot++, keyBlocks[keyBlocksIndex][0xF]++)
|
||||
{
|
||||
aes(decKey, keyBlocks[keyBlocksIndex], 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
|
||||
if(!ISSIGHAX) return;
|
||||
|
||||
twlConsoleInfoInit();
|
||||
|
||||
if(k9lVersion == 2)
|
||||
{
|
||||
aes_setkey(0x11, key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
|
||||
{
|
||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
aes(decKey, keyBlocks[0], 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(0x18, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,12 +590,18 @@ void computePinHash(u8 *outbuf, const u8 *inbuf)
|
||||
|
||||
void backupAndRestoreShaHash(bool isRestore)
|
||||
{
|
||||
if(ISA9LH)
|
||||
if(!ISA9LH) return;
|
||||
|
||||
static bool didShaHashBackup = false;
|
||||
__attribute__((aligned(4))) static u8 shaHashBackup[SHA_256_HASH_SIZE];
|
||||
|
||||
if(isRestore)
|
||||
{
|
||||
if(isRestore)
|
||||
{
|
||||
if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup));
|
||||
}
|
||||
else if(!didShaHashBackup) memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup));
|
||||
if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup));
|
||||
}
|
||||
}
|
||||
else if(!didShaHashBackup)
|
||||
{
|
||||
memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup));
|
||||
didShaHashBackup = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
||||
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
||||
|
||||
#define REGs_AESTWLKEYS (*((vu32 (*)[4][3][4])0x10009040))
|
||||
|
||||
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
||||
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
||||
#define AES_CTR_MODE (2u << 27)
|
||||
@@ -113,4 +115,4 @@ bool decryptExeFs(Cxi *cxi);
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
void kernel9Loader(Arm9Bin *arm9Section);
|
||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||
void backupAndRestoreShaHash(bool isRestore);
|
||||
void backupAndRestoreShaHash(bool isRestore);
|
||||
|
||||
@@ -38,31 +38,23 @@ bool loadSplash(void)
|
||||
*bottomSplashFile = "splashbottom.bin";
|
||||
|
||||
bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE,
|
||||
isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE,
|
||||
ret;
|
||||
isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
//Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD
|
||||
if(!isTopSplashValid && !isBottomSplashValid) ret = false;
|
||||
else
|
||||
{
|
||||
initScreens();
|
||||
clearScreens(true, true, true);
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
|
||||
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
|
||||
initScreens();
|
||||
clearScreens(true);
|
||||
|
||||
if(!isTopSplashValid && !isBottomSplashValid) ret = false;
|
||||
else
|
||||
{
|
||||
swapFramebuffers(true);
|
||||
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
|
||||
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
chrono(3);
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
swapFramebuffers(true);
|
||||
wait(3000ULL);
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color)
|
||||
|
||||
128
source/emunand.c
128
source/emunand.c
@@ -36,7 +36,6 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
static u8 __attribute__((aligned(4))) temp[0x200];
|
||||
static u32 nandSize = 0,
|
||||
fatStart;
|
||||
bool found = false;
|
||||
|
||||
if(!nandSize)
|
||||
{
|
||||
@@ -45,7 +44,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < 3 && !found; i++)
|
||||
for(u32 i = 0; i < 3; i++)
|
||||
{
|
||||
static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000};
|
||||
|
||||
@@ -58,7 +57,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
case 2:
|
||||
nandOffset = roundedMinsizes[ISN3DS ? 1 : 0]; //"Minsize" layout
|
||||
break;
|
||||
default:
|
||||
case 0:
|
||||
nandOffset = *nandType == FIRMWARE_EMUNAND ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //"Legacy" layout
|
||||
break;
|
||||
}
|
||||
@@ -72,7 +71,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
{
|
||||
emuOffset = nandOffset + 1;
|
||||
*emuHeader = nandOffset + 1;
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//Check for Gateway EmuNAND
|
||||
@@ -80,7 +79,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
{
|
||||
emuOffset = nandOffset;
|
||||
*emuHeader = nandOffset + nandSize;
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,136 +87,109 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||
}
|
||||
|
||||
//Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any
|
||||
if(!found)
|
||||
if(*nandType != FIRMWARE_EMUNAND)
|
||||
{
|
||||
if(*nandType != FIRMWARE_EMUNAND)
|
||||
{
|
||||
*nandType = FIRMWARE_EMUNAND;
|
||||
locateEmuNand(emuHeader, nandType);
|
||||
}
|
||||
else *nandType = FIRMWARE_SYSNAND;
|
||||
*nandType = FIRMWARE_EMUNAND;
|
||||
locateEmuNand(emuHeader, nandType);
|
||||
}
|
||||
else *nandType = FIRMWARE_SYSNAND;
|
||||
}
|
||||
|
||||
static inline u32 getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
||||
static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||
u32 ret;
|
||||
|
||||
//Looking for the last free space before Process9
|
||||
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(*freeK9Space == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
*freeK9Space += 0x455;
|
||||
if(*freeK9Space == NULL) return false;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
*freeK9Space += 0x455;
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
||||
{
|
||||
//Look for struct code
|
||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||
u32 ret;
|
||||
|
||||
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
||||
{
|
||||
//Look for read/write code
|
||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||
u32 ret;
|
||||
|
||||
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(readOffset == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
readOffset -= 3;
|
||||
if(readOffset == NULL) return 1;
|
||||
|
||||
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
|
||||
readOffset -= 3;
|
||||
|
||||
if(writeOffset == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
writeOffset -= 3;
|
||||
*readOffset = *writeOffset = 0x4C00;
|
||||
readOffset[1] = writeOffset[1] = 0x47A0;
|
||||
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
|
||||
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if(writeOffset == NULL) return 1;
|
||||
|
||||
return ret;
|
||||
writeOffset -= 3;
|
||||
*readOffset = *writeOffset = 0x4C00;
|
||||
readOffset[1] = writeOffset[1] = 0x47A0;
|
||||
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 patchMpu(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for MPU pattern
|
||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[1] = 0x0036;
|
||||
off[0xC] = off[0x12] = 0x0603;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[1] = 0x0036;
|
||||
off[0xC] = off[0x12] = 0x0603;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u32 emuHeader, u8 *kernel9Address)
|
||||
{
|
||||
u8 *freeK9Space;
|
||||
|
||||
if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1;
|
||||
|
||||
u32 ret = 0;
|
||||
|
||||
u8 *freeK9Space;
|
||||
ret += getFreeK9Space(arm9Section, kernel9Size, &freeK9Space);
|
||||
//Copy EmuNAND code
|
||||
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
//Copy EmuNAND code
|
||||
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
|
||||
//Add the data of the found EmuNAND
|
||||
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
|
||||
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
|
||||
*posOffset = emuOffset;
|
||||
*posHeader = emuHeader;
|
||||
|
||||
//Add the data of the found EmuNAND
|
||||
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
|
||||
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
|
||||
*posOffset = emuOffset;
|
||||
*posHeader = emuHeader;
|
||||
//Find and add the SDMMC struct
|
||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
||||
u32 sdmmc;
|
||||
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||
if(!ret) *posSdmmc = sdmmc;
|
||||
|
||||
//Find and add the SDMMC struct
|
||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
||||
u32 sdmmc;
|
||||
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||
if(!ret) *posSdmmc = sdmmc;
|
||||
//Add EmuNAND hooks
|
||||
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
|
||||
ret += patchNandRw(process9Offset, process9Size, branchOffset);
|
||||
|
||||
//Add EmuNAND hooks
|
||||
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
|
||||
ret += patchNandRw(process9Offset, process9Size, branchOffset);
|
||||
|
||||
//Set MPU
|
||||
ret += patchMpu(arm9Section, kernel9Size);
|
||||
}
|
||||
//Set MPU
|
||||
ret += patchMpu(arm9Section, kernel9Size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -45,9 +45,8 @@ void installArm9Handlers(void)
|
||||
}
|
||||
}
|
||||
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset)
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset, u32 *dAbtHandler, u32 dAbtHandlerMemAddress)
|
||||
{
|
||||
u32 ret;
|
||||
u32 *endPos = exceptionsPage + 0x400;
|
||||
|
||||
u32 *initFPU;
|
||||
@@ -59,152 +58,165 @@ u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffse
|
||||
u32 *mcuReboot;
|
||||
for(mcuReboot = exceptionsPage; mcuReboot < endPos && *mcuReboot != 0xE3A0A0C2; mcuReboot++);
|
||||
|
||||
if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) ret = 1;
|
||||
else
|
||||
if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) return 1;
|
||||
|
||||
initFPU += 3;
|
||||
mcuReboot -= 2;
|
||||
|
||||
memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32);
|
||||
|
||||
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 8) - 32); //Undefined Instruction
|
||||
exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 12) - 32); //Prefetch Abort
|
||||
exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4) - 32); //FIQ
|
||||
|
||||
for(u32 *pos = dAbtHandler; *pos != stackAddress; pos++)
|
||||
{
|
||||
initFPU += 3;
|
||||
mcuReboot -= 2;
|
||||
|
||||
memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32);
|
||||
|
||||
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 8) - 32); //Undefined Instruction
|
||||
exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 12) - 32); //Prefetch Abort
|
||||
exceptionsPage[4] = MAKE_BRANCH(exceptionsPage + 4, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 16) - 32); //Data Abort
|
||||
exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4) - 32); //FIQ
|
||||
|
||||
for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 32); pos++)
|
||||
u32 va_dst = 0xFFFF0000 + (((u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4)) - (u8 *)exceptionsPage);
|
||||
u32 va_src;
|
||||
switch(*pos)
|
||||
{
|
||||
switch(*pos) //Perform relocations
|
||||
{
|
||||
case 0xFFFF3000: *pos = stackAddress; break;
|
||||
case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break;
|
||||
case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break;
|
||||
case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler)
|
||||
case 0xBEEFBEEF: *pos = codeSetOffset; break;
|
||||
}
|
||||
case 0xF96D0513: //srsdb sp!, 0x13
|
||||
va_src = dAbtHandlerMemAddress + ((u8 *)pos - (u8 *)dAbtHandler);
|
||||
*pos = MAKE_BRANCH((u8 *)va_src, (u8 *)va_dst);
|
||||
break;
|
||||
case 0xE29EF004: //subs pc, lr, 4
|
||||
pos++;
|
||||
*pos++ = 0xE8BD000F;// pop {r0-r3}
|
||||
va_src = dAbtHandlerMemAddress + ((u8 *)pos - (u8 *)dAbtHandler);
|
||||
*pos = MAKE_BRANCH((u8 *)va_src, (u8 *)va_dst);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 32); pos++)
|
||||
{
|
||||
switch(*pos) //Perform relocations
|
||||
{
|
||||
case 0xFFFF3000: *pos = stackAddress - 0x10; break;
|
||||
case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break;
|
||||
case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break;
|
||||
case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler)
|
||||
case 0xBEEFBEEF: *pos = codeSetOffset; break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void detectAndProcessExceptionDumps(void)
|
||||
{
|
||||
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
|
||||
|
||||
if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11))
|
||||
if(dumpHeader->magic[0] != 0xDEADC0DE || dumpHeader->magic[1] != 0xDEADCAFE || (dumpHeader->processor != 9 && dumpHeader->processor != 11)) return;
|
||||
|
||||
const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
|
||||
const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize;
|
||||
const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize;
|
||||
|
||||
const char *handledExceptionNames[] = {
|
||||
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
||||
};
|
||||
|
||||
const char *specialExceptions[] = {
|
||||
"(kernel panic)", "(svcBreak)"
|
||||
};
|
||||
|
||||
const char *registerNames[] = {
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
||||
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||
};
|
||||
|
||||
char hexString[] = "00000000";
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString("An exception occurred", true, 10, 10, COLOR_RED);
|
||||
u32 posY = drawString(dumpHeader->processor == 11 ? "Processor: ARM11 (core )" : "Processor: ARM9", true, 10, 30, COLOR_WHITE);
|
||||
if(dumpHeader->processor == 11) drawCharacter('0' + dumpHeader->core, true, 10 + 29 * SPACING_X, 30, COLOR_WHITE);
|
||||
|
||||
posY = drawString("Exception type: ", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
drawString(handledExceptionNames[dumpHeader->type], true, 10 + 17 * SPACING_X, posY, COLOR_WHITE);
|
||||
|
||||
if(dumpHeader->type == 2)
|
||||
{
|
||||
const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
|
||||
const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize;
|
||||
const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize;
|
||||
|
||||
const char *handledExceptionNames[] = {
|
||||
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
||||
};
|
||||
|
||||
const char *specialExceptions[] = {
|
||||
"(kernel panic)", "(svcBreak)"
|
||||
};
|
||||
|
||||
const char *registerNames[] = {
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
||||
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||
};
|
||||
|
||||
char hexString[] = "00000000";
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString("An exception occurred", true, 10, 10, COLOR_RED);
|
||||
u32 posY = drawString(dumpHeader->processor == 11 ? "Processor: ARM11 (core )" : "Processor: ARM9", true, 10, 30, COLOR_WHITE);
|
||||
if(dumpHeader->processor == 11) drawCharacter('0' + dumpHeader->core, true, 10 + 29 * SPACING_X, 30, COLOR_WHITE);
|
||||
|
||||
posY = drawString("Exception type: ", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
drawString(handledExceptionNames[dumpHeader->type], true, 10 + 17 * SPACING_X, posY, COLOR_WHITE);
|
||||
|
||||
if(dumpHeader->type == 2)
|
||||
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
||||
{
|
||||
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
||||
{
|
||||
u32 instr = *(vu32 *)(stackDump - 4);
|
||||
if(instr == 0xE12FFF7E) drawString(specialExceptions[0], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
else if(instr == 0xEF00003C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
else if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 2)
|
||||
{
|
||||
u16 instr = *(vu16 *)(stackDump - 2);
|
||||
if(instr == 0xDF3C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
u32 instr = *(vu32 *)(stackDump - 4);
|
||||
if(instr == 0xE12FFF7E) drawString(specialExceptions[0], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
else if(instr == 0xEF00003C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||
else if((regs[16] & 0x20) != 0 && dumpHeader->codeDumpSize >= 2)
|
||||
{
|
||||
char processName[] = "Current process: ";
|
||||
memcpy(processName + sizeof(processName) - 9, (void *)additionalData, 8);
|
||||
posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
u16 instr = *(vu16 *)(stackDump - 2);
|
||||
if(instr == 0xDF3C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
for(u32 i = 0; i < 17; i += 2)
|
||||
{
|
||||
posY = drawString(registerNames[i], true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
hexItoa(regs[i], hexString, 8, true);
|
||||
drawString(hexString, true, 10 + 7 * SPACING_X, posY, COLOR_WHITE);
|
||||
|
||||
if(i != 16 || dumpHeader->processor != 9)
|
||||
{
|
||||
drawString(registerNames[i + 1], true, 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
||||
hexItoa(i == 16 ? regs[20] : regs[i + 1], hexString, 8, true);
|
||||
drawString(hexString, true, 10 + 29 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
u32 mode = regs[16] & 0xF;
|
||||
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
||||
posY = drawString("Incorrect dump: failed to dump code and/or stack", true, 10, posY + SPACING_Y, COLOR_YELLOW) + SPACING_Y;
|
||||
|
||||
u32 posYBottom = drawString("Stack dump:", false, 10, 10, COLOR_WHITE) + SPACING_Y;
|
||||
|
||||
for(u32 line = 0; line < 19 && stackDump < additionalData; line++)
|
||||
{
|
||||
hexItoa(regs[13] + 8 * line, hexString, 8, true);
|
||||
posYBottom = drawString(hexString, false, 10, posYBottom + SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter(':', false, 10 + 8 * SPACING_X, posYBottom, COLOR_WHITE);
|
||||
|
||||
for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++)
|
||||
{
|
||||
char byteString[] = "00";
|
||||
hexItoa(*stackDump, byteString, 2, false);
|
||||
drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
char path[36];
|
||||
char fileName[] = "crash_dump_00000000.dmp";
|
||||
const char *pathFolder = dumpHeader->processor == 9 ? "dumps/arm9" : "dumps/arm11";
|
||||
|
||||
findDumpFile(pathFolder, fileName);
|
||||
memcpy(path, pathFolder, strlen(pathFolder) + 1);
|
||||
concatenateStrings(path, "/");
|
||||
concatenateStrings(path, fileName);
|
||||
|
||||
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
||||
{
|
||||
posY = drawString("You can find a dump in the following file:", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
posY = drawString(path, true, 10, posY + SPACING_Y, COLOR_WHITE) + SPACING_Y;
|
||||
}
|
||||
else posY = drawString("Error writing the dump file", true, 10, posY + SPACING_Y, COLOR_RED);
|
||||
|
||||
drawString("Press any button to shutdown", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
|
||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||
|
||||
waitInput();
|
||||
mcuPowerOff();
|
||||
}
|
||||
}
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||
{
|
||||
char processName[] = "Current process: ";
|
||||
memcpy(processName + sizeof(processName) - 9, (void *)additionalData, 8);
|
||||
posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
for(u32 i = 0; i < 17; i += 2)
|
||||
{
|
||||
posY = drawString(registerNames[i], true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
hexItoa(regs[i], hexString, 8, true);
|
||||
drawString(hexString, true, 10 + 7 * SPACING_X, posY, COLOR_WHITE);
|
||||
|
||||
if(i != 16 || dumpHeader->processor != 9)
|
||||
{
|
||||
drawString(registerNames[i + 1], true, 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
||||
hexItoa(i == 16 ? regs[20] : regs[i + 1], hexString, 8, true);
|
||||
drawString(hexString, true, 10 + 29 * SPACING_X, posY, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
u32 mode = regs[16] & 0xF;
|
||||
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
||||
posY = drawString("Incorrect dump: failed to dump code and/or stack", true, 10, posY + SPACING_Y, COLOR_YELLOW) + SPACING_Y;
|
||||
|
||||
u32 posYBottom = drawString("Stack dump:", false, 10, 10, COLOR_WHITE) + SPACING_Y;
|
||||
|
||||
for(u32 line = 0; line < 19 && stackDump < additionalData; line++)
|
||||
{
|
||||
hexItoa(regs[13] + 8 * line, hexString, 8, true);
|
||||
posYBottom = drawString(hexString, false, 10, posYBottom + SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter(':', false, 10 + 8 * SPACING_X, posYBottom, COLOR_WHITE);
|
||||
|
||||
for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++)
|
||||
{
|
||||
char byteString[] = "00";
|
||||
hexItoa(*stackDump, byteString, 2, false);
|
||||
drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
char path[36] = "dumps/",
|
||||
fileName[] = "crash_dump_00000000.dmp";
|
||||
|
||||
concatenateStrings(path, dumpHeader->processor == 9 ? "arm9" : "arm11");
|
||||
findDumpFile(path, fileName);
|
||||
concatenateStrings(path, "/");
|
||||
concatenateStrings(path, fileName);
|
||||
|
||||
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
||||
{
|
||||
posY = drawString("You can find a dump in the following file:", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
posY = drawString(path, true, 10, posY + SPACING_Y, COLOR_WHITE) + SPACING_Y;
|
||||
}
|
||||
else posY = drawString("Error writing the dump file", true, 10, posY + SPACING_Y, COLOR_RED);
|
||||
|
||||
drawString("Press any button to shutdown", true, 10, posY + SPACING_Y, COLOR_WHITE);
|
||||
|
||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||
|
||||
waitInput(false);
|
||||
mcuPowerOff();
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
|
||||
void installArm9Handlers(void);
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset);
|
||||
void detectAndProcessExceptionDumps(void);
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset, u32 *dAbtHandler, u32 dAbtHandlerMemAddress);
|
||||
void detectAndProcessExceptionDumps(void);
|
||||
|
||||
13
source/fatfs/00history.txt
Executable file → Normal file
13
source/fatfs/00history.txt
Executable file → Normal file
@@ -212,7 +212,7 @@ R0.10a (January 15, 2014)
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ R0.12a (July 10, 2016)
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Improved f_rename() to be able to rename objects with the same name but case.
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
@@ -277,3 +277,12 @@ R0.12b (September 04, 2016)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
26
source/fatfs/00readme.txt
Executable file → Normal file
26
source/fatfs/00readme.txt
Executable file → Normal file
@@ -1,21 +1,21 @@
|
||||
FatFs Module Source Files R0.12a
|
||||
FatFs Module Source Files R0.12c
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
history.txt Revision history.
|
||||
ffconf.h Configuration file for FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
ff.c FatFs module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external functions.
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external modules.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module that written
|
||||
to control the target storage device.
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
||||
|
||||
737
source/fatfs/ff.c
Executable file → Normal file
737
source/fatfs/ff.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
25
source/fatfs/ff.h
Executable file → Normal file
25
source/fatfs/ff.h
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12b /
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||
/ Copyright (C) 2017, 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
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 68020 /* Revision ID */
|
||||
#define _FATFS 68300 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -42,13 +42,6 @@ typedef struct {
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -140,14 +133,15 @@ typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
@@ -163,7 +157,7 @@ typedef struct {
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
@@ -185,7 +179,7 @@ typedef struct {
|
||||
_FDID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if _USE_LFN != 0
|
||||
@@ -285,6 +279,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
|
||||
23
source/fatfs/ffconf.h
Executable file → Normal file
23
source/fatfs/ffconf.h
Executable file → Normal file
@@ -2,7 +2,7 @@
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 68020 /* Revision ID */
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
@@ -73,7 +73,7 @@
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
@@ -148,7 +148,7 @@
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 2
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
@@ -172,11 +172,11 @@
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
@@ -204,7 +204,7 @@
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
@@ -212,20 +212,20 @@
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards C89 compatibility. */
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2016
|
||||
#define _NORTC_YEAR 2017
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
|
||||
@@ -258,10 +258,11 @@
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
2
source/fatfs/integer.h
Executable file → Normal file
2
source/fatfs/integer.h
Executable file → Normal file
@@ -30,7 +30,7 @@ typedef unsigned short WCHAR;
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
/* This type MUST be 64-bit (Remove this for C89 compatibility) */
|
||||
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
|
||||
typedef unsigned long long QWORD;
|
||||
|
||||
#endif
|
||||
|
||||
0
source/fatfs/option/ccsbcs.c
Executable file → Normal file
0
source/fatfs/option/ccsbcs.c
Executable file → Normal file
156
source/firm.c
156
source/firm.c
@@ -36,21 +36,47 @@
|
||||
|
||||
static Firm *firm = (Firm *)0x24000000;
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
{
|
||||
const char *firmwareFiles[] = {
|
||||
"firmware.bin",
|
||||
"firmware_twl.bin",
|
||||
"firmware_agb.bin",
|
||||
"firmware_safe.bin"
|
||||
"firmware_safe.bin",
|
||||
"firmware_sysupdater.bin"
|
||||
},
|
||||
*cetkFiles[] = {
|
||||
"cetk",
|
||||
"cetk_twl",
|
||||
"cetk_agb",
|
||||
"cetk_safe"
|
||||
"cetk_safe",
|
||||
"cetk_sysupdater"
|
||||
};
|
||||
|
||||
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
|
||||
|
||||
if(!firmSize) return false;
|
||||
|
||||
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
|
||||
|
||||
if(memcmp(firm, "FIRM", 4) != 0)
|
||||
{
|
||||
u8 cetk[0xA50];
|
||||
|
||||
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) ||
|
||||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
|
||||
error("The FIRM in /luma is encrypted or corrupted.");
|
||||
}
|
||||
|
||||
//Check that the FIRM is right for the console from the ARM9 section address
|
||||
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
|
||||
error("The FIRM in /luma is not for this console.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||
|
||||
@@ -63,7 +89,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
||||
if(firmVersion < 0x18)
|
||||
{
|
||||
//We can't boot < 3.x EmuNANDs
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
||||
|
||||
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||
@@ -75,32 +101,8 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
||||
else if(firmVersion < 0x25) mustLoadFromStorage = true;
|
||||
}
|
||||
|
||||
if(loadFromStorage || mustLoadFromStorage)
|
||||
{
|
||||
u32 firmSize = fileRead(firm, *firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)*firmType], 0x400000 + sizeof(Cxi) + 0x200);
|
||||
|
||||
if(firmSize > 0)
|
||||
{
|
||||
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
|
||||
|
||||
if(memcmp(firm, "FIRM", 4) != 0)
|
||||
{
|
||||
u8 cetk[0xA50];
|
||||
|
||||
if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) != sizeof(cetk) ||
|
||||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
|
||||
error("The FIRM in /luma is encrypted or corrupted.");
|
||||
}
|
||||
|
||||
//Check that the FIRM is right for the console from the ARM9 section address
|
||||
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
|
||||
error("The FIRM in /luma is not for this console.");
|
||||
|
||||
firmVersion = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if(firmVersion != 0xFFFFFFFF)
|
||||
if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF;
|
||||
else
|
||||
{
|
||||
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
|
||||
if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
|
||||
@@ -110,7 +112,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, u32 devMode)
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
||||
@@ -134,8 +136,9 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
||||
u32 baseK11VA;
|
||||
u8 *freeK11Space;
|
||||
u32 *arm11SvcHandler,
|
||||
*arm11DAbtHandler,
|
||||
*arm11ExceptionsPage,
|
||||
*arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage);
|
||||
*arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11DAbtHandler, &arm11ExceptionsPage);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
@@ -169,22 +172,25 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
||||
ret += reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
||||
}
|
||||
|
||||
//Stub svc 0x59 on 11.3+ FIRMs
|
||||
if(firmVersion >= (ISN3DS ? 0x2D : 0x5C)) ret += stubSvcRestrictGpuDma(arm11Section1, arm11SvcTable, baseK11VA);
|
||||
|
||||
ret += implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space, isSafeMode);
|
||||
|
||||
//Apply UNITINFO patches
|
||||
if(devMode == 2)
|
||||
if(doUnitinfoPatch)
|
||||
{
|
||||
ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
if(!ISDEVUNIT) ret += patchCheckForDevCommonKey(process9Offset, process9Size);
|
||||
}
|
||||
|
||||
if(devMode != 0 && isA9lhInstalled)
|
||||
if(enableExceptionHandlers && isA9lhInstalled)
|
||||
{
|
||||
//ARM11 exception handlers
|
||||
u32 codeSetOffset,
|
||||
stackAddress = getInfoForArm11ExceptionHandlers(arm11Section1, firm->section[1].size, &codeSetOffset);
|
||||
ret += installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset);
|
||||
patchSvcBreak11(arm11Section1, arm11SvcTable);
|
||||
ret += installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset, arm11DAbtHandler, baseK11VA + ((u8 *)arm11DAbtHandler - arm11Section1));
|
||||
patchSvcBreak11(arm11Section1, arm11SvcTable, baseK11VA);
|
||||
ret += patchKernel11Panic(arm11Section1, firm->section[1].size);
|
||||
|
||||
//ARM9 exception handlers
|
||||
@@ -193,20 +199,27 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
||||
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
||||
}
|
||||
|
||||
if(CONFIG(PATCHACCESS))
|
||||
bool patchAccess = CONFIG(PATCHACCESS),
|
||||
patchGames = CONFIG(PATCHGAMES);
|
||||
|
||||
if(patchAccess || patchGames)
|
||||
{
|
||||
ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size));
|
||||
ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space);
|
||||
ret += patchP9AccessChecks(process9Offset, process9Size);
|
||||
ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space, patchGames);
|
||||
|
||||
if(patchAccess)
|
||||
{
|
||||
ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size));
|
||||
ret += patchP9AccessChecks(process9Offset, process9Size);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchTwlFirm(u32 firmVersion, u32 devMode)
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
if(ISN3DS)
|
||||
{
|
||||
@@ -231,15 +244,15 @@ u32 patchTwlFirm(u32 firmVersion, u32 devMode)
|
||||
ret += patchTwlShaHashChecks(process9Offset, process9Size);
|
||||
|
||||
//Apply UNITINFO patch
|
||||
if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchAgbFirm(u32 devMode)
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
if(ISN3DS)
|
||||
{
|
||||
@@ -259,12 +272,12 @@ u32 patchAgbFirm(u32 devMode)
|
||||
if(CONFIG(SHOWGBABOOT)) ret += patchAgbBootSplash(process9Offset, process9Size);
|
||||
|
||||
//Apply UNITINFO patch
|
||||
if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patch1x2xNativeAndSafeFirm(u32 devMode)
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
||||
|
||||
@@ -285,7 +298,9 @@ u32 patch1x2xNativeAndSafeFirm(u32 devMode)
|
||||
|
||||
ret += ISN3DS ? patchFirmWrites(process9Offset, process9Size) : patchOldFirmWrites(process9Offset, process9Size);
|
||||
|
||||
if(devMode != 0)
|
||||
ret += ISN3DS ? patchSignatureChecks(process9Offset, process9Size) : patchOldSignatureChecks(process9Offset, process9Size);
|
||||
|
||||
if(enableExceptionHandlers)
|
||||
{
|
||||
//ARM9 exception handlers
|
||||
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
||||
@@ -308,10 +323,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
|
||||
srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
bool loadedModule;
|
||||
|
||||
if(!loadFromStorage) loadedModule = false;
|
||||
else
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24] = "sysmodules/";
|
||||
|
||||
@@ -321,8 +333,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
|
||||
|
||||
dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(dstModuleSize == 0) loadedModule = false;
|
||||
else
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
@@ -332,29 +343,26 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo
|
||||
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
loadedModule = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!loadedModule)
|
||||
const u8 *module;
|
||||
|
||||
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||
{
|
||||
const u8 *module;
|
||||
|
||||
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||
{
|
||||
module = injector_bin;
|
||||
dstModuleSize = injector_bin_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
module = src;
|
||||
dstModuleSize = srcModuleSize;
|
||||
}
|
||||
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
memcpy(dst, module, dstModuleSize);
|
||||
module = injector_bin;
|
||||
dstModuleSize = injector_bin_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
module = src;
|
||||
dstModuleSize = srcModuleSize;
|
||||
}
|
||||
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
memcpy(dst, module, dstModuleSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +370,7 @@ void launchFirm(FirmwareType firmType, bool loadFromStorage)
|
||||
{
|
||||
//Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs
|
||||
u32 sectionNum;
|
||||
if(firmType == NATIVE_FIRM || (loadFromStorage && firmType != SAFE_FIRM && firmType != NATIVE_FIRM1X2X))
|
||||
if(firmType == NATIVE_FIRM || (loadFromStorage && (firmType == TWL_FIRM || firmType == AGB_FIRM)))
|
||||
{
|
||||
copySection0AndInjectSystemModules(firmType, loadFromStorage);
|
||||
sectionNum = 1;
|
||||
@@ -391,4 +399,4 @@ void launchFirm(FirmwareType firmType, bool loadFromStorage)
|
||||
|
||||
//Final jump to ARM9 kernel
|
||||
((void (*)())firm->arm9Entry)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "types.h"
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, u32 devMode);
|
||||
u32 patchTwlFirm(u32 firmVersion, u32 devMode);
|
||||
u32 patchAgbFirm(u32 devMode);
|
||||
u32 patch1x2xNativeAndSafeFirm(u32 devMode);
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lhInstalled, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage);
|
||||
|
||||
291
source/fs.c
291
source/fs.c
@@ -26,6 +26,9 @@
|
||||
#include "crypto.h"
|
||||
#include "cache.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "fatfs/ff.h"
|
||||
#include "buttons.h"
|
||||
#include "../build/bundled.h"
|
||||
@@ -36,23 +39,17 @@ static FATFS sdFs,
|
||||
static bool switchToMainDir(bool isSd)
|
||||
{
|
||||
const char *mainDir = isSd ? "/luma" : "/rw/luma";
|
||||
bool ret;
|
||||
|
||||
switch(f_chdir(mainDir))
|
||||
{
|
||||
case FR_OK:
|
||||
ret = true;
|
||||
break;
|
||||
return true;
|
||||
case FR_NO_PATH:
|
||||
f_mkdir(mainDir);
|
||||
ret = switchToMainDir(isSd);
|
||||
break;
|
||||
return switchToMainDir(isSd);
|
||||
default:
|
||||
ret = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mountFs(bool isSd, bool switchToCtrNand)
|
||||
@@ -64,17 +61,15 @@ bool mountFs(bool isSd, bool switchToCtrNand)
|
||||
u32 fileRead(void *dest, const char *path, u32 maxSize)
|
||||
{
|
||||
FIL file;
|
||||
u32 ret;
|
||||
u32 ret = 0;
|
||||
|
||||
if(f_open(&file, path, FA_READ) != FR_OK) ret = 0;
|
||||
else
|
||||
{
|
||||
u32 size = f_size(&file);
|
||||
if(dest == NULL) ret = size;
|
||||
else if(size <= maxSize)
|
||||
f_read(&file, dest, size, (unsigned int *)&ret);
|
||||
f_close(&file);
|
||||
}
|
||||
if(f_open(&file, path, FA_READ) != FR_OK) return ret;
|
||||
|
||||
u32 size = f_size(&file);
|
||||
if(dest == NULL) ret = size;
|
||||
else if(size <= maxSize)
|
||||
f_read(&file, dest, size, (unsigned int *)&ret);
|
||||
f_close(&file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -87,7 +82,6 @@ u32 getFileSize(const char *path)
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||
{
|
||||
FIL file;
|
||||
bool ret;
|
||||
|
||||
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
|
||||
{
|
||||
@@ -98,8 +92,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||
f_truncate(&file);
|
||||
f_close(&file);
|
||||
|
||||
ret = (u32)written == size;
|
||||
break;
|
||||
return (u32)written == size;
|
||||
}
|
||||
case FR_NO_PATH:
|
||||
for(u32 i = 1; path[i] != 0; i++)
|
||||
@@ -111,14 +104,10 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||
f_mkdir(folder);
|
||||
}
|
||||
|
||||
ret = fileWrite(buffer, path, size);
|
||||
break;
|
||||
return fileWrite(buffer, path, size);
|
||||
default:
|
||||
ret = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fileDelete(const char *path)
|
||||
@@ -126,67 +115,164 @@ void fileDelete(const char *path)
|
||||
f_unlink(path);
|
||||
}
|
||||
|
||||
void loadPayload(u32 pressed)
|
||||
void loadPayload(u32 pressed, const char *payloadPath)
|
||||
{
|
||||
const char *pattern;
|
||||
u32 *loaderAddress = (u32 *)0x24FFFE00;
|
||||
u8 *payloadAddress = (u8 *)0x24F00000;
|
||||
u32 payloadSize = 0,
|
||||
maxPayloadSize = (u32)((u8 *)loaderAddress - payloadAddress);
|
||||
|
||||
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
|
||||
else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
|
||||
else if(pressed & BUTTON_UP) pattern = PATTERN("up");
|
||||
else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
|
||||
else if(pressed & BUTTON_START) pattern = PATTERN("start");
|
||||
else if(pressed & BUTTON_B) pattern = PATTERN("b");
|
||||
else if(pressed & BUTTON_X) pattern = PATTERN("x");
|
||||
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
|
||||
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
|
||||
else if(pressed & BUTTON_A) pattern = PATTERN("a");
|
||||
else pattern = PATTERN("select");
|
||||
|
||||
DIR dir;
|
||||
FILINFO info;
|
||||
char path[22] = "payloads";
|
||||
|
||||
FRESULT result = f_findfirst(&dir, &info, path, pattern);
|
||||
|
||||
if(result == FR_OK)
|
||||
if(payloadPath == NULL)
|
||||
{
|
||||
const char *pattern;
|
||||
|
||||
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
|
||||
else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
|
||||
else if(pressed & BUTTON_UP) pattern = PATTERN("up");
|
||||
else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
|
||||
else if(pressed & BUTTON_START) pattern = PATTERN("start");
|
||||
else if(pressed & BUTTON_B) pattern = PATTERN("b");
|
||||
else if(pressed & BUTTON_X) pattern = PATTERN("x");
|
||||
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
|
||||
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
|
||||
else if(pressed & BUTTON_A) pattern = PATTERN("a");
|
||||
else pattern = PATTERN("select");
|
||||
|
||||
DIR dir;
|
||||
FILINFO info;
|
||||
FRESULT result;
|
||||
char path[22] = "payloads";
|
||||
|
||||
result = f_findfirst(&dir, &info, path, pattern);
|
||||
|
||||
if(result != FR_OK) return;
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(info.fname[0] != 0)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x24FFFE00;
|
||||
u8 *payloadAddress = (u8 *)0x24F00000;
|
||||
if(!info.fname[0]) return;
|
||||
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
|
||||
concatenateStrings(path, "/");
|
||||
concatenateStrings(path, info.altname);
|
||||
|
||||
u32 payloadSize = fileRead(payloadAddress, path, (u32)((u8 *)loaderAddress - payloadAddress));
|
||||
|
||||
if(payloadSize > 0)
|
||||
{
|
||||
loaderAddress[1] = payloadSize;
|
||||
|
||||
backupAndRestoreShaHash(true);
|
||||
initScreens();
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)())loaderAddress)();
|
||||
}
|
||||
}
|
||||
concatenateStrings(path, "/");
|
||||
concatenateStrings(path, info.altname);
|
||||
payloadSize = fileRead(payloadAddress, path, maxPayloadSize);
|
||||
}
|
||||
else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize);
|
||||
|
||||
if(!payloadSize) return;
|
||||
|
||||
writeConfig(true);
|
||||
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
loaderAddress[1] = payloadSize;
|
||||
|
||||
backupAndRestoreShaHash(true);
|
||||
initScreens();
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)())loaderAddress)();
|
||||
}
|
||||
|
||||
void payloadMenu(void)
|
||||
{
|
||||
DIR dir;
|
||||
char path[62] = "payloads";
|
||||
|
||||
if(f_opendir(&dir, path) != FR_OK) return;
|
||||
|
||||
FILINFO info;
|
||||
u32 payloadNum = 0;
|
||||
char payloadList[20][49];
|
||||
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20)
|
||||
{
|
||||
if(info.fname[0] == '.') continue;
|
||||
|
||||
u32 nameLength = strlen(info.fname);
|
||||
|
||||
if(nameLength < 5 || nameLength > 52) continue;
|
||||
|
||||
nameLength -= 4;
|
||||
|
||||
if(memcmp(info.fname + nameLength, ".bin", 4) != 0) continue;
|
||||
|
||||
memcpy(payloadList[payloadNum], info.fname, nameLength);
|
||||
payloadList[payloadNum][nameLength] = 0;
|
||||
payloadNum++;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(!payloadNum) return;
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE);
|
||||
drawString("Press A to select, START to quit", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||
|
||||
for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
||||
{
|
||||
drawString(payloadList[i], true, 10, posY, color);
|
||||
if(color == COLOR_RED) color = COLOR_WHITE;
|
||||
}
|
||||
|
||||
u32 pressed = 0,
|
||||
selectedPayload = 0;
|
||||
|
||||
while(pressed != BUTTON_A && pressed != BUTTON_START)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput(true);
|
||||
}
|
||||
while(!(pressed & MENU_BUTTONS));
|
||||
|
||||
u32 oldSelectedPayload = selectedPayload;
|
||||
|
||||
switch(pressed)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
selectedPayload = !selectedPayload ? payloadNum - 1 : selectedPayload - 1;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
selectedPayload = selectedPayload == payloadNum - 1 ? 0 : selectedPayload + 1;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
selectedPayload = 0;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
selectedPayload = payloadNum - 1;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if(oldSelectedPayload == selectedPayload) continue;
|
||||
|
||||
drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE);
|
||||
drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED);
|
||||
}
|
||||
|
||||
if(pressed == BUTTON_A)
|
||||
{
|
||||
concatenateStrings(path, "/");
|
||||
concatenateStrings(path, payloadList[selectedPayload]);
|
||||
concatenateStrings(path, ".bin");
|
||||
loadPayload(0, path);
|
||||
error("The payload is too large or corrupted.");
|
||||
}
|
||||
|
||||
while(HID_PAD & MENU_BUTTONS);
|
||||
wait(2000ULL);
|
||||
}
|
||||
|
||||
u32 firmRead(void *dest, u32 firmType)
|
||||
{
|
||||
const char *firmFolders[][2] = {{ "00000002", "20000002" },
|
||||
{ "00000102", "20000102" },
|
||||
{ "00000202", "20000202" },
|
||||
{ "00000003", "20000003" },
|
||||
{ "00000001", "20000001" }};
|
||||
const char *firmFolders[][2] = {{"00000002", "20000002"},
|
||||
{"00000102", "20000102"},
|
||||
{"00000202", "20000202"},
|
||||
{"00000003", "20000003"},
|
||||
{"00000001", "20000001"}};
|
||||
|
||||
char path[48] = "1:/title/00040138/";
|
||||
concatenateStrings(path, firmFolders[firmType][ISN3DS ? 1 : 0]);
|
||||
@@ -195,36 +281,35 @@ u32 firmRead(void *dest, u32 firmType)
|
||||
DIR dir;
|
||||
u32 firmVersion = 0xFFFFFFFF;
|
||||
|
||||
if(f_opendir(&dir, path) == FR_OK)
|
||||
if(f_opendir(&dir, path) != FR_OK) goto exit;
|
||||
|
||||
FILINFO info;
|
||||
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||
{
|
||||
FILINFO info;
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||
{
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||
u32 tempVersion = hexAtoi(info.altname, 8);
|
||||
|
||||
u32 tempVersion = hexAtoi(info.altname, 8);
|
||||
|
||||
//Found an older cxi
|
||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(firmVersion != 0xFFFFFFFF)
|
||||
{
|
||||
//Complete the string with the .app name
|
||||
concatenateStrings(path, "/00000000.app");
|
||||
|
||||
//Convert back the .app name from integer to array
|
||||
hexItoa(firmVersion, path + 35, 8, false);
|
||||
|
||||
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
|
||||
}
|
||||
//Found an older cxi
|
||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(firmVersion == 0xFFFFFFFF) goto exit;
|
||||
|
||||
//Complete the string with the .app name
|
||||
concatenateStrings(path, "/00000000.app");
|
||||
|
||||
//Convert back the .app name from integer to array
|
||||
hexItoa(firmVersion, path + 35, 8, false);
|
||||
|
||||
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
|
||||
|
||||
exit:
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize);
|
||||
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, const char *payloadPath);
|
||||
void payloadMenu(void);
|
||||
u32 firmRead(void *dest, u32 firmType);
|
||||
void findDumpFile(const char *path, char *fileName);
|
||||
25
source/i2c.c
25
source/i2c.c
@@ -115,6 +115,31 @@ static bool i2cSelectRegister(u8 bus_id, u8 reg)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg)
|
||||
{
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||
dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr | 1))
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
i2cStop(bus_id, 1);
|
||||
i2cWaitBusy(bus_id);
|
||||
|
||||
return *i2cGetDataReg(bus_id);
|
||||
}
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||
{
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||
|
||||
@@ -41,4 +41,5 @@
|
||||
#define I2C_DEV_GYRO 10
|
||||
#define I2C_DEV_IR 13
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg);
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
||||
285
source/main.c
285
source/main.c
@@ -30,19 +30,20 @@
|
||||
#include "strings.h"
|
||||
#include "buttons.h"
|
||||
#include "pin.h"
|
||||
#include "crypto.h"
|
||||
|
||||
extern CfgData configData;
|
||||
extern ConfigurationStatus needConfig;
|
||||
extern FirmwareSource firmSource;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bool isA9lhInstalled,
|
||||
isSafeMode = false;
|
||||
u32 configTemp,
|
||||
emuHeader;
|
||||
isSafeMode = false,
|
||||
isNoForceFlagSet = false;
|
||||
u32 emuHeader;
|
||||
FirmwareType firmType;
|
||||
FirmwareSource nandType;
|
||||
ConfigurationStatus needConfig;
|
||||
|
||||
//Mount SD or CTRNAND
|
||||
bool isSdMode;
|
||||
@@ -78,146 +79,145 @@ void main(void)
|
||||
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||
isA9lhInstalled = BOOTCFG_A9LH != 0;
|
||||
|
||||
goto boot;
|
||||
}
|
||||
else
|
||||
|
||||
if(ISA9LH)
|
||||
{
|
||||
if(ISA9LH)
|
||||
detectAndProcessExceptionDumps();
|
||||
installArm9Handlers();
|
||||
}
|
||||
|
||||
firmType = NATIVE_FIRM;
|
||||
isA9lhInstalled = ISA9LH;
|
||||
|
||||
//Get pressed buttons
|
||||
u32 pressed = HID_PAD;
|
||||
|
||||
//If it's a MCU reboot, try to force boot options
|
||||
if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
|
||||
{
|
||||
|
||||
//Always force a SysNAND boot when quitting AGB_FIRM
|
||||
if(CFG_BOOTENV == 7)
|
||||
{
|
||||
detectAndProcessExceptionDumps();
|
||||
installArm9Handlers();
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
|
||||
|
||||
//Prevent multiple boot options-forcing
|
||||
isNoForceFlagSet = true;
|
||||
|
||||
goto boot;
|
||||
}
|
||||
|
||||
firmType = NATIVE_FIRM;
|
||||
isA9lhInstalled = ISA9LH;
|
||||
|
||||
//Get pressed buttons
|
||||
u32 pressed = HID_PAD;
|
||||
|
||||
//Save old options and begin saving the new boot configuration
|
||||
configTemp = (configData.config & 0xFFFFFF00) | ((u32)ISA9LH << 6);
|
||||
|
||||
//If it's a MCU reboot, try to force boot options
|
||||
if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
|
||||
/* Else, force the last used boot options unless a button is pressed
|
||||
or the no-forcing flag is set */
|
||||
if(!pressed && !BOOTCFG_NOFORCEFLAG)
|
||||
{
|
||||
//Always force a SysNAND boot when quitting AGB_FIRM
|
||||
if(CFG_BOOTENV == 7)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
|
||||
needConfig = DONT_CONFIGURE;
|
||||
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||
|
||||
//Flag to prevent multiple boot options-forcing
|
||||
configTemp |= 1 << 7;
|
||||
}
|
||||
|
||||
/* Else, force the last used boot options unless a button is pressed
|
||||
or the no-forcing flag is set */
|
||||
else if(!pressed && !BOOTCFG_NOFORCEFLAG)
|
||||
{
|
||||
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||
needConfig = DONT_CONFIGURE;
|
||||
}
|
||||
}
|
||||
|
||||
//Boot options aren't being forced
|
||||
if(needConfig != DONT_CONFIGURE)
|
||||
{
|
||||
u32 pinMode = MULTICONFIG(PIN);
|
||||
bool pinExists = pinMode != 0 && verifyPin(pinMode);
|
||||
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT);
|
||||
|
||||
if(shouldLoadConfigMenu)
|
||||
{
|
||||
configMenu(isSdMode, pinExists, pinMode);
|
||||
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
|
||||
if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
|
||||
isSafeMode = true;
|
||||
|
||||
//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
|
||||
{
|
||||
u32 splashMode = MULTICONFIG(SPLASH);
|
||||
|
||||
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
||||
|
||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||
chainload an external payload */
|
||||
bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1));
|
||||
|
||||
if(shouldLoadPayload) loadPayload(pressed);
|
||||
|
||||
if(splashMode == 2) loadSplash();
|
||||
|
||||
//If booting from CTRNAND, always use SysNAND
|
||||
if(!isSdMode) nandType = FIRMWARE_SYSNAND;
|
||||
|
||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||
else if(pressed & BUTTON_R1)
|
||||
{
|
||||
if(CONFIG(USESYSFIRM))
|
||||
{
|
||||
nandType = FIRMWARE_EMUNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_EMUNAND;
|
||||
}
|
||||
}
|
||||
|
||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||
with their own FIRM */
|
||||
else firmSource = nandType = (CONFIG(AUTOBOOTSYS) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||
|
||||
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
|
||||
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
||||
{
|
||||
FirmwareSource tempNand;
|
||||
switch(pressed & EMUNAND_BUTTONS)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
tempNand = FIRMWARE_EMUNAND;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
tempNand = FIRMWARE_EMUNAND2;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
tempNand = FIRMWARE_EMUNAND3;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
tempNand = FIRMWARE_EMUNAND4;
|
||||
break;
|
||||
default:
|
||||
tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
|
||||
break;
|
||||
}
|
||||
|
||||
if(nandType == FIRMWARE_EMUNAND) nandType = tempNand;
|
||||
else firmSource = tempNand;
|
||||
}
|
||||
}
|
||||
goto boot;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pinMode = MULTICONFIG(PIN);
|
||||
bool pinExists = pinMode != 0 && verifyPin(pinMode);
|
||||
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT);
|
||||
|
||||
if(shouldLoadConfigMenu)
|
||||
{
|
||||
configMenu(isSdMode, pinExists, pinMode);
|
||||
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
|
||||
if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
|
||||
isSafeMode = true;
|
||||
|
||||
//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);
|
||||
wait(2000ULL);
|
||||
}
|
||||
|
||||
goto boot;
|
||||
}
|
||||
|
||||
u32 splashMode = MULTICONFIG(SPLASH);
|
||||
|
||||
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
||||
|
||||
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
|
||||
{
|
||||
payloadMenu();
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
|
||||
|
||||
if(splashMode == 2) loadSplash();
|
||||
|
||||
//If booting from CTRNAND, always use SysNAND
|
||||
if(!isSdMode) nandType = FIRMWARE_SYSNAND;
|
||||
|
||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||
else if(pressed & BUTTON_R1)
|
||||
{
|
||||
if(CONFIG(USESYSFIRM))
|
||||
{
|
||||
nandType = FIRMWARE_EMUNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_EMUNAND;
|
||||
}
|
||||
}
|
||||
|
||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||
with their own FIRM */
|
||||
else firmSource = nandType = (CONFIG(AUTOBOOTSYS) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||
|
||||
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
|
||||
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
||||
{
|
||||
FirmwareSource tempNand;
|
||||
switch(pressed & DPAD_BUTTONS)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
tempNand = FIRMWARE_EMUNAND;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
tempNand = FIRMWARE_EMUNAND2;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
tempNand = FIRMWARE_EMUNAND3;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
tempNand = FIRMWARE_EMUNAND4;
|
||||
break;
|
||||
default:
|
||||
tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
|
||||
break;
|
||||
}
|
||||
|
||||
if(nandType == FIRMWARE_EMUNAND) nandType = tempNand;
|
||||
else firmSource = tempNand;
|
||||
}
|
||||
|
||||
boot:
|
||||
|
||||
//If we need to boot EmuNAND, make sure it exists
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
{
|
||||
@@ -231,8 +231,8 @@ void main(void)
|
||||
|
||||
if(!ISFIRMLAUNCH)
|
||||
{
|
||||
configTemp |= (u32)nandType | ((u32)firmSource << 3);
|
||||
writeConfig(needConfig, configTemp);
|
||||
configData.config = (configData.config & 0xFFFFFF00) | ((u32)isNoForceFlagSet << 7) | ((u32)ISA9LH << 6) | ((u32)firmSource << 3) | (u32)nandType;
|
||||
writeConfig(false);
|
||||
}
|
||||
|
||||
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
|
||||
@@ -240,24 +240,23 @@ void main(void)
|
||||
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
|
||||
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
|
||||
|
||||
u32 devMode = MULTICONFIG(DEVOPTIONS);
|
||||
|
||||
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), enableExceptionHandlers = CONFIG(ENABLEEXCEPTIONHANDLERS);
|
||||
u32 res;
|
||||
switch(firmType)
|
||||
{
|
||||
case NATIVE_FIRM:
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, isSafeMode, devMode);
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
break;
|
||||
case TWL_FIRM:
|
||||
res = patchTwlFirm(firmVersion, devMode);
|
||||
res = patchTwlFirm(firmVersion, doUnitinfoPatch);
|
||||
break;
|
||||
case AGB_FIRM:
|
||||
res = patchAgbFirm(devMode);
|
||||
res = patchAgbFirm(doUnitinfoPatch);
|
||||
break;
|
||||
case SAFE_FIRM:
|
||||
case SYSUPDATER_FIRM:
|
||||
case NATIVE_FIRM1X2X:
|
||||
res = isA9lhInstalled ? patch1x2xNativeAndSafeFirm(devMode) : 0;
|
||||
res = isA9lhInstalled ? patch1x2xNativeAndSafeFirm(enableExceptionHandlers) : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -269,4 +268,4 @@ void main(void)
|
||||
}
|
||||
|
||||
launchFirm(firmType, loadFromStorage);
|
||||
}
|
||||
}
|
||||
|
||||
628
source/patches.c
628
source/patches.c
@@ -22,10 +22,12 @@
|
||||
|
||||
/*
|
||||
* Signature patches by an unknown author
|
||||
* Signature patches for old FIRMs by SciresM
|
||||
* firmlaunches patching code originally by delebile
|
||||
* FIRM partition writes patches by delebile
|
||||
* ARM11 modules patching code originally by Subv
|
||||
* Idea for svcBreak patches from yellows8 and others on #3dsdev
|
||||
* TWL_FIRM patches by Steveice10 and others
|
||||
*/
|
||||
|
||||
#include "patches.h"
|
||||
@@ -35,6 +37,30 @@
|
||||
#include "utils.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
static inline void pathChanger(u8 *pos)
|
||||
{
|
||||
const char *pathFile = "path.txt";
|
||||
u8 path[57];
|
||||
|
||||
u32 pathSize = fileRead(path, pathFile, sizeof(path));
|
||||
|
||||
if(pathSize < 6) return;
|
||||
|
||||
if(path[pathSize - 1] == 0xA) pathSize--;
|
||||
if(path[pathSize - 1] == 0xD) pathSize--;
|
||||
|
||||
if(pathSize < 6 || pathSize > 55 || path[0] != '/' || memcmp(path + pathSize - 4, ".bin", 4) != 0) return;
|
||||
|
||||
u16 finalPath[56];
|
||||
for(u32 i = 0; i < pathSize; i++)
|
||||
finalPath[i] = (u16)path[i];
|
||||
|
||||
finalPath[pathSize] = 0;
|
||||
|
||||
u8 *posPath = memsearch(pos, u"sd", reboot_bin_size, 4) + 0xA;
|
||||
memcpy(posPath, finalPath, (pathSize + 1) * 2);
|
||||
}
|
||||
|
||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||
{
|
||||
u8 *temp = memsearch(pos, "NCCH", size, 4);
|
||||
@@ -49,34 +75,29 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||
return (u8 *)off + (off->ncch.exeFsOffset + 1) * 0x200;
|
||||
}
|
||||
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11DAbtHandler, u32 **arm11ExceptionsPage)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5};
|
||||
bool res = true;
|
||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5},
|
||||
pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
*arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
*freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
if(*arm11ExceptionsPage == NULL || *freeK11Space == NULL) error("Failed to get Kernel11 data.");
|
||||
|
||||
u32 *arm11SvcTable;
|
||||
|
||||
if(*arm11ExceptionsPage == NULL) res = false;
|
||||
else
|
||||
{
|
||||
*arm11ExceptionsPage -= 0xB;
|
||||
u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||
u32 pointedInstructionVA = 0xFFFF0008 - svcOffset;
|
||||
*baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case
|
||||
arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address
|
||||
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
|
||||
}
|
||||
*arm11ExceptionsPage -= 0xB;
|
||||
u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||
u32 dabtOffset = (-(((*arm11ExceptionsPage)[4] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||
u32 pointedInstructionVA = 0xFFFF0008 - svcOffset;
|
||||
*baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case
|
||||
arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //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));
|
||||
|
||||
if(*freeK11Space == NULL) res = false;
|
||||
else (*freeK11Space)++;
|
||||
|
||||
if(!res) error("Failed to get Kernel11 data.");
|
||||
pointedInstructionVA = 0xFFFF0010 - dabtOffset;
|
||||
*arm11DAbtHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA);
|
||||
(*freeK11Space)++;
|
||||
|
||||
return arm11SvcTable;
|
||||
}
|
||||
@@ -86,207 +107,157 @@ u32 patchSignatureChecks(u8 *pos, u32 size)
|
||||
//Look for signature checks
|
||||
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
||||
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
if(off == NULL || temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u16 *off2 = (u16 *)(temp - 1);
|
||||
if(off == NULL || temp == NULL) return 1;
|
||||
|
||||
*off = off2[0] = 0x2000;
|
||||
off2[1] = 0x4770;
|
||||
u16 *off2 = (u16 *)(temp - 1);
|
||||
*off = off2[0] = 0x2000;
|
||||
off2[1] = 0x4770;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
u32 patchOldSignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
// Look for signature checks
|
||||
const u8 pattern[] = {0xC0, 0x1C, 0xBD, 0xE7},
|
||||
pattern2[] = {0xB5, 0x23, 0x4E, 0x0C};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
if(off == NULL || temp == NULL) return 1;
|
||||
|
||||
u16 *off2 = (u16 *)(temp - 1);
|
||||
*off = off2[0] = 0x2000;
|
||||
off2[1] = 0x4770;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
|
||||
{
|
||||
//Look for firmlaunch code
|
||||
const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
|
||||
u32 ret;
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off -= 0x13;
|
||||
if(off == NULL) return 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);
|
||||
off -= 0x13;
|
||||
|
||||
//Copy firmlaunch code
|
||||
memcpy(off, reboot_bin, reboot_bin_size);
|
||||
//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);
|
||||
|
||||
//Put the fOpen offset in the right location
|
||||
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
||||
*pos_fopen = fOpenOffset;
|
||||
//Copy firmlaunch code
|
||||
memcpy(off, reboot_bin, reboot_bin_size);
|
||||
|
||||
ret = 0;
|
||||
//Put the fOpen offset in the right location
|
||||
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
||||
*pos_fopen = fOpenOffset;
|
||||
|
||||
if(CONFIG(USECUSTOMPATH))
|
||||
{
|
||||
const char *pathFile = "path.txt";
|
||||
if(CONFIG(USECUSTOMPATH)) pathChanger(off);
|
||||
|
||||
u32 pathSize = getFileSize(pathFile);
|
||||
|
||||
if(pathSize > 5 && pathSize < 58)
|
||||
{
|
||||
u8 path[pathSize];
|
||||
fileRead(path, pathFile, pathSize);
|
||||
if(path[pathSize - 1] == 0xA) pathSize--;
|
||||
if(path[pathSize - 1] == 0xD) pathSize--;
|
||||
|
||||
if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0)
|
||||
{
|
||||
u16 finalPath[pathSize];
|
||||
for(u32 i = 0; i < pathSize; i++)
|
||||
finalPath[i] = (u16)path[i];
|
||||
|
||||
u8 *pos_path = memsearch(off, u"sd", reboot_bin_size, 4) + 0xA;
|
||||
memcpy(pos_path, finalPath, pathSize * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchFirmWrites(u8 *pos, u32 size)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
//Look for FIRM writing code
|
||||
u8 *off = memsearch(pos, "exe:", size, 4);
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||
if(off == NULL) return 1;
|
||||
|
||||
u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern));
|
||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||
|
||||
if(off2 == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off2[0] = 0x2000;
|
||||
off2[1] = 0x46C0;
|
||||
u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern));
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if(off2 == NULL) return 1;
|
||||
|
||||
return ret;
|
||||
off2[0] = 0x2000;
|
||||
off2[1] = 0x46C0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchOldFirmWrites(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for FIRM writing code
|
||||
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[0] = 0x2400;
|
||||
off[1] = 0xE01D;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[0] = 0x2400;
|
||||
off[1] = 0xE01D;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion)
|
||||
{
|
||||
const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02};
|
||||
u32 ret;
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = firmVersion == 0xFFFFFFFF ? 0 : 1;
|
||||
else
|
||||
{
|
||||
off++;
|
||||
if(off == NULL) return firmVersion == 0xFFFFFFFF ? 0 : 1;
|
||||
|
||||
memset32(off, 0, 8); //Zero out the first TitleID in the list
|
||||
off++;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
//Zero out the first TitleID in the list
|
||||
memset32(off, 0, 8);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
*off = 0x2001; //mov r0, #1
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off--;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
*off = 0x2001; //mov r0, #1
|
||||
off--;
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
*off = 0x2301; //mov r3, #1
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
*off = 0x2301; //mov r3, #1
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
|
||||
{
|
||||
u32 ret = 0;
|
||||
if(arm11SvcTable[0x7B] != 0) return 0;
|
||||
|
||||
//Official implementation of svcBackdoor
|
||||
const u8 svcBackdoor[] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
|
||||
@@ -300,137 +271,118 @@ u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
|
||||
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
|
||||
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
|
||||
|
||||
if(!arm11SvcTable[0x7B])
|
||||
{
|
||||
if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) ret = 1;
|
||||
else
|
||||
{
|
||||
memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor));
|
||||
if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) return 1;
|
||||
|
||||
arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos;
|
||||
*freeK11Space += sizeof(svcBackdoor);
|
||||
}
|
||||
memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor));
|
||||
|
||||
arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos;
|
||||
*freeK11Space += sizeof(svcBackdoor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA)
|
||||
{
|
||||
if(arm11SvcTable[0x59] != 0)
|
||||
{
|
||||
u32 *off = (u32 *)(pos + arm11SvcTable[0x59] - baseK11VA);
|
||||
off[1] = 0xE1A00000; //replace call to inner function by a NOP
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode)
|
||||
{
|
||||
u32 ret;
|
||||
if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) return 1;
|
||||
|
||||
if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) ret = 1;
|
||||
else
|
||||
memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size);
|
||||
|
||||
struct CfwInfo
|
||||
{
|
||||
memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size);
|
||||
char magic[4];
|
||||
|
||||
struct CfwInfo
|
||||
{
|
||||
char magic[4];
|
||||
u8 versionMajor;
|
||||
u8 versionMinor;
|
||||
u8 versionBuild;
|
||||
u8 flags;
|
||||
|
||||
u8 versionMajor;
|
||||
u8 versionMinor;
|
||||
u8 versionBuild;
|
||||
u8 flags;
|
||||
u32 commitHash;
|
||||
|
||||
u32 commitHash;
|
||||
u32 config;
|
||||
} __attribute__((packed)) *info = (struct CfwInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_bin_size, 4);
|
||||
|
||||
u32 config;
|
||||
} __attribute__((packed)) *info = (struct CfwInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_bin_size, 4);
|
||||
const char *rev = REVISION;
|
||||
|
||||
const char *rev = REVISION;
|
||||
info->commitHash = COMMIT_HASH;
|
||||
info->config = configData.config;
|
||||
info->versionMajor = (u8)(rev[1] - '0');
|
||||
info->versionMinor = (u8)(rev[3] - '0');
|
||||
|
||||
info->commitHash = COMMIT_HASH;
|
||||
info->config = configData.config;
|
||||
info->versionMajor = (u8)(rev[1] - '0');
|
||||
info->versionMinor = (u8)(rev[3] - '0');
|
||||
bool isRelease;
|
||||
|
||||
bool isRelease;
|
||||
|
||||
if(rev[4] == '.')
|
||||
{
|
||||
info->versionBuild = (u8)(rev[5] - '0');
|
||||
isRelease = rev[6] == 0;
|
||||
}
|
||||
else isRelease = rev[4] == 0;
|
||||
|
||||
if(isRelease) info->flags = 1;
|
||||
|
||||
if(ISN3DS) info->flags |= 1 << 4;
|
||||
|
||||
if(isSafeMode) info->flags |= 1 << 5;
|
||||
|
||||
arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc
|
||||
*freeK11Space += svcGetCFWInfo_bin_size;
|
||||
|
||||
ret = 0;
|
||||
if(rev[4] == '.')
|
||||
{
|
||||
info->versionBuild = (u8)(rev[5] - '0');
|
||||
isRelease = rev[6] == 0;
|
||||
}
|
||||
else isRelease = rev[4] == 0;
|
||||
|
||||
return ret;
|
||||
if(isRelease) info->flags = 1;
|
||||
if(ISN3DS) info->flags |= 1 << 4;
|
||||
if(isSafeMode) info->flags |= 1 << 5;
|
||||
|
||||
arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc
|
||||
*freeK11Space += svcGetCFWInfo_bin_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u32 *off = (u32 *)(temp - 0xA);
|
||||
|
||||
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
|
||||
{
|
||||
u32 *off = (u32 *)(temp - 0xA);
|
||||
//Discard everything that's not str rX, [r0, #imm](!)
|
||||
if((*off & 0xFE5F0000) != 0xE4000000) continue;
|
||||
|
||||
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
|
||||
{
|
||||
//Discard everything that's not str rX, [r0, #imm](!)
|
||||
if((*off & 0xFE5F0000) == 0xE4000000)
|
||||
{
|
||||
u32 rD = (*off >> 12) & 0xF,
|
||||
offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1);
|
||||
bool writeback = ((*off >> 21) & 1) != 0,
|
||||
pre = ((*off >> 24) & 1) != 0;
|
||||
u32 rD = (*off >> 12) & 0xF,
|
||||
offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1);
|
||||
bool writeback = ((*off >> 21) & 1) != 0,
|
||||
pre = ((*off >> 24) & 1) != 0;
|
||||
|
||||
u32 addr = r0 + ((pre || !writeback) ? offset : 0);
|
||||
if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop
|
||||
else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers
|
||||
u32 addr = r0 + ((pre || !writeback) ? offset : 0);
|
||||
if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop
|
||||
else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers
|
||||
|
||||
if(!pre) addr += offset;
|
||||
if(writeback) r0 = addr;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if(!pre) addr += offset;
|
||||
if(writeback) r0 = addr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset)
|
||||
{
|
||||
const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet
|
||||
pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher
|
||||
bool ret = true;
|
||||
|
||||
u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(loadCodeSet == NULL) ret = false;
|
||||
else
|
||||
{
|
||||
loadCodeSet -= 2;
|
||||
*codeSetOffset = *loadCodeSet & 0xFFF;
|
||||
}
|
||||
|
||||
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
u32 stackAddress;
|
||||
if(loadCodeSet == NULL || temp == NULL) error("Failed to get ARM11 exception handlers data.");
|
||||
|
||||
if(temp == NULL) ret = false;
|
||||
else stackAddress = *(u32 *)(temp + 9);
|
||||
loadCodeSet -= 2;
|
||||
*codeSetOffset = *loadCodeSet & 0xFFF;
|
||||
|
||||
if(!ret) error("Failed to get ARM11 exception handlers data.");
|
||||
|
||||
return stackAddress;
|
||||
return *(u32 *)(temp + 9);
|
||||
}
|
||||
|
||||
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
|
||||
@@ -439,319 +391,237 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
|
||||
|
||||
//Look for the svc handler
|
||||
const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
|
||||
u32 ret;
|
||||
|
||||
u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(arm9SvcTable == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL)
|
||||
if(arm9SvcTable == NULL) return 1;
|
||||
|
||||
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
|
||||
*addr = 0xE12FFF7F;
|
||||
while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL)
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
|
||||
*addr = 0xE12FFF7F;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
|
||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA)
|
||||
{
|
||||
//Same as above, for NATIVE_FIRM ARM11
|
||||
u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000);
|
||||
u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - baseK11VA);
|
||||
*addr = 0xE12FFF7F;
|
||||
}
|
||||
|
||||
u32 patchKernel9Panic(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u32 *off = (u32 *)(temp - 0x12);
|
||||
*off = 0xE12FFF7E;
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
u32 *off = (u32 *)(temp - 0x12);
|
||||
*off = 0xE12FFF7E;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchKernel11Panic(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2};
|
||||
u32 ret;
|
||||
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
*off = 0xE12FFF7E;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
*off = 0xE12FFF7E;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchP9AccessChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x08, 0x49, 0x68};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u16 *off = (u16 *)(temp - 3);
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770; //bx lr
|
||||
u16 *off = (u16 *)(temp - 3);
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770; //bx lr
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR
|
||||
|
||||
if(arm11SvcHandler == endPos) ret = 1;
|
||||
else
|
||||
{
|
||||
*arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1
|
||||
if(arm11SvcHandler == endPos) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
*arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
|
||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames)
|
||||
{
|
||||
/* We have to detour a function in the ARM11 kernel because builtin modules
|
||||
are compressed in memory and are only decompressed at runtime */
|
||||
|
||||
u32 ret;
|
||||
|
||||
//Check that we have enough free space
|
||||
if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) ret = 0;
|
||||
else
|
||||
{
|
||||
//Look for the code that decompresses the .code section of the builtin modules
|
||||
const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
|
||||
if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return patchGames ? 1 : 0;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
//Look for the code that decompresses the .code section of the builtin modules
|
||||
const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
//Inject our code into the free space
|
||||
memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size);
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
u32 *off = (u32 *)(temp - 0xB);
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
//Inject a jump (BL) instruction to our code at the offset we found
|
||||
*off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF);
|
||||
//Inject our code into the free space
|
||||
memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size);
|
||||
|
||||
*freeK11Space += k11modules_bin_size;
|
||||
u32 *off = (u32 *)(temp - 0xB);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
//Inject a jump (BL) instruction to our code at the offset we found
|
||||
*off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF);
|
||||
|
||||
return ret;
|
||||
*freeK11Space += k11modules_bin_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchUnitInfoValueSet(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for UNITINFO value being set during kernel sync
|
||||
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
|
||||
u32 ret;
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[0] = ISDEVUNIT ? 0 : 1;
|
||||
off[3] = 0xE3;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[0] = ISDEVUNIT ? 0 : 1;
|
||||
off[3] = 0xE3;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchLgySignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u16 *off = (u16 *)(temp + 1);
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
off[0] = 0x2000;
|
||||
off[1] = 0xB04E;
|
||||
off[2] = 0xBD70;
|
||||
u16 *off = (u16 *)(temp + 1);
|
||||
off[0] = 0x2000;
|
||||
off[1] = 0xB04E;
|
||||
off[2] = 0xBD70;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
*off = 0x2001; //mov r0, #1
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[1] = 0x2000;
|
||||
off[2] = 0;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[1] = 0x2000;
|
||||
off[2] = 0;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlWhitelistChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x22, 0x00, 0x20, 0x30};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[2] = 0x2000;
|
||||
off[3] = 0;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[2] = 0x2000;
|
||||
off[3] = 0;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion)
|
||||
{
|
||||
const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E};
|
||||
u32 ret;
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL)
|
||||
{
|
||||
if(firmVersion == 0xFFFFFFFF) ret = patchOldTwlFlashcartChecks(pos, size);
|
||||
else ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 *off = (u16 *)(temp + 3);
|
||||
if(firmVersion == 0xFFFFFFFF) return patchOldTwlFlashcartChecks(pos, size);
|
||||
|
||||
off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = off[0xD] = 0; //nop
|
||||
|
||||
ret = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
u16 *off = (u16 *)(temp + 3);
|
||||
off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = off[0xD] = 0; //nop
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[0] = off[6] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = 0; //nop
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[0] = off[6] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = 0; //nop
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlShaHashChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22};
|
||||
u32 ret;
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF};
|
||||
u32 ret;
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) ret = 1;
|
||||
else
|
||||
{
|
||||
off[2] = 0x26;
|
||||
if(off == NULL) return 1;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
off[2] = 0x26;
|
||||
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,12 @@
|
||||
|
||||
/*
|
||||
* Signature patches by an unknown author
|
||||
* Signature patches for old FIRMs by SciresM
|
||||
* firmlaunches patching code originally by delebile
|
||||
* FIRM partition writes patches by delebile
|
||||
* ARM11 modules patching code originally by Subv
|
||||
* Idea for svcBreak patches from yellows8 and others on #3dsdev
|
||||
* TWL_FIRM patches by Steveice10 and others
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -35,8 +37,9 @@
|
||||
extern CfgData configData;
|
||||
|
||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage);
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11DAbtHandler, u32 **arm11ExceptionsPage);
|
||||
u32 patchSignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchOldSignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||
u32 patchFirmWrites(u8 *pos, u32 size);
|
||||
u32 patchOldFirmWrites(u8 *pos, u32 size);
|
||||
@@ -45,16 +48,17 @@ u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size);
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
||||
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
||||
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode);
|
||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
||||
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset);
|
||||
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address);
|
||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable);
|
||||
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
||||
u32 patchKernel9Panic(u8 *pos, u32 size);
|
||||
u32 patchKernel11Panic(u8 *pos, u32 size);
|
||||
u32 patchP9AccessChecks(u8 *pos, u32 size);
|
||||
u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos);
|
||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space);
|
||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames);
|
||||
u32 patchUnitInfoValueSet(u8 *pos, u32 size);
|
||||
u32 patchLgySignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size);
|
||||
@@ -63,4 +67,4 @@ u32 patchTwlWhitelistChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlShaHashChecks(u8 *pos, u32 size);
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size);
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size);
|
||||
|
||||
122
source/pin.c
122
source/pin.c
@@ -46,27 +46,37 @@ static char pinKeyToLetter(u32 pressed)
|
||||
|
||||
void newPin(bool allowSkipping, u32 pinMode)
|
||||
{
|
||||
clearScreens(true, true, false);
|
||||
clearScreens(false);
|
||||
|
||||
u8 length = 4 + 2 * (pinMode - 1);
|
||||
|
||||
const char *title = allowSkipping ? "Press START to skip or enter a new PIN" : "Enter a new PIN to proceed";
|
||||
drawString(title, true, 10, 10, COLOR_TITLE);
|
||||
drawString("PIN ( digits): ", true, 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter('0' + length, true, 10 + 5 * SPACING_X, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
drawString("Enter a new PIN using ABXY and the DPad", true, 10, 10, COLOR_TITLE);
|
||||
drawString(allowSkipping ? "Press START to skip, SELECT to reset" : "Press SELECT to reset", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||
|
||||
drawString("PIN ( digits): ", true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter('0' + length, true, 10 + 5 * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
//Pad to AES block length with zeroes
|
||||
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
bool reset = false;
|
||||
u8 cnt = 0;
|
||||
u32 charDrawPos = 16 * SPACING_X;
|
||||
|
||||
while(cnt < length)
|
||||
{
|
||||
if(reset)
|
||||
{
|
||||
for(u32 i = 0; i < cnt; i++)
|
||||
drawCharacter((char)enteredPassword[i], true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK);
|
||||
|
||||
cnt = 0;
|
||||
reset = false;
|
||||
}
|
||||
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
pressed = waitInput(false);
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
@@ -74,14 +84,22 @@ void newPin(bool allowSkipping, u32 pinMode)
|
||||
if(!allowSkipping) pressed &= ~BUTTON_START;
|
||||
|
||||
if(pressed & BUTTON_START) return;
|
||||
|
||||
if(pressed & BUTTON_SELECT)
|
||||
{
|
||||
reset = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!pressed) continue;
|
||||
|
||||
char key = pinKeyToLetter(pressed);
|
||||
enteredPassword[cnt++] = (u8)key; //Add character to password
|
||||
//Add character to password
|
||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||
|
||||
//Visualize character on screen
|
||||
drawCharacter(key, true, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
charDrawPos += 2 * SPACING_X;
|
||||
drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
PinData pin;
|
||||
@@ -125,38 +143,45 @@ bool verifyPin(u32 pinMode)
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString("Enter the PIN using ABXY and the DPad to proceed", true, 10, 10, COLOR_TITLE);
|
||||
drawString("Press START to shutdown, SELECT to clear", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||
|
||||
drawString("PIN ( digits): ", true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter('0' + lengthBlock[0], true, 10 + 5 * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
const char *messageFile = "pinmessage.txt";
|
||||
char message[801];
|
||||
|
||||
u32 messageSize = fileRead(message, messageFile, sizeof(message) - 1);
|
||||
|
||||
if(messageSize != 0)
|
||||
{
|
||||
message[messageSize] = 0;
|
||||
drawString(message, false, 10, 10, COLOR_WHITE);
|
||||
}
|
||||
|
||||
//Pad to AES block length with zeroes
|
||||
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
bool unlock = false;
|
||||
bool unlock = false,
|
||||
reset = false;
|
||||
u8 cnt = 0;
|
||||
u32 charDrawPos = 16 * SPACING_X;
|
||||
|
||||
const char *messageFile = "pinmessage.txt";
|
||||
|
||||
u32 messageSize = getFileSize(messageFile);
|
||||
|
||||
if(messageSize > 0 && messageSize <= 800)
|
||||
{
|
||||
char message[messageSize + 1];
|
||||
|
||||
if(fileRead(message, messageFile, messageSize) == messageSize)
|
||||
{
|
||||
message[messageSize] = 0;
|
||||
drawString(message, false, 10, 10, COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
while(!unlock)
|
||||
{
|
||||
drawString("Press START to shutdown or enter PIN to proceed", true, 10, 10, COLOR_TITLE);
|
||||
drawString("PIN ( digits): ", true, 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
drawCharacter('0' + lengthBlock[0], true, 10 + 5 * SPACING_X, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
if(reset)
|
||||
{
|
||||
for(u32 i = 0; i < cnt; i++)
|
||||
drawCharacter('*', true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK);
|
||||
|
||||
cnt = 0;
|
||||
reset = false;
|
||||
}
|
||||
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
pressed = waitInput(false);
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
@@ -164,29 +189,30 @@ bool verifyPin(u32 pinMode)
|
||||
|
||||
pressed &= PIN_BUTTONS;
|
||||
|
||||
if(pressed & BUTTON_SELECT)
|
||||
{
|
||||
reset = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!pressed) continue;
|
||||
|
||||
char key = pinKeyToLetter(pressed);
|
||||
enteredPassword[cnt++] = (u8)key; //Add character to password
|
||||
//Add character to password
|
||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||
|
||||
//Visualize character on screen
|
||||
drawCharacter(key, true, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
charDrawPos += 2 * SPACING_X;
|
||||
drawCharacter('*', true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
if(cnt >= lengthBlock[0])
|
||||
if(++cnt < lengthBlock[0]) continue;
|
||||
|
||||
computePinHash(tmp, enteredPassword);
|
||||
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
|
||||
|
||||
if(!unlock)
|
||||
{
|
||||
computePinHash(tmp, enteredPassword);
|
||||
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
|
||||
reset = true;
|
||||
|
||||
if(!unlock)
|
||||
{
|
||||
charDrawPos = 16 * SPACING_X;
|
||||
cnt = 0;
|
||||
|
||||
clearScreens(true, false, false);
|
||||
|
||||
drawString("Wrong PIN, try again", true, 10, 10 + 4 * SPACING_Y, COLOR_RED);
|
||||
}
|
||||
drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,31 +40,30 @@
|
||||
#include "memory.h"
|
||||
#include "cache.h"
|
||||
#include "i2c.h"
|
||||
#include "utils.h"
|
||||
|
||||
vu32 *arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
|
||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||
|
||||
void __attribute__((naked)) arm11Stub(void)
|
||||
{
|
||||
//Wait for the entry to be set
|
||||
while(*arm11Entry == ARM11_STUB_ADDRESS);
|
||||
|
||||
//Jump to it
|
||||
((void (*)())*arm11Entry)();
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
|
||||
static void invokeArm11Function(void (*func)())
|
||||
{
|
||||
static bool hasCopiedStub = false;
|
||||
|
||||
if(!hasCopiedStub)
|
||||
{
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x2C);
|
||||
hasCopiedStub = true;
|
||||
}
|
||||
|
||||
*arm11Entry = (u32)func;
|
||||
while(*arm11Entry);
|
||||
*arm11Entry = ARM11_STUB_ADDRESS;
|
||||
while(*arm11Entry);
|
||||
}
|
||||
|
||||
void deinitScreens(void)
|
||||
@@ -82,7 +81,7 @@ void deinitScreens(void)
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
if(ARESCREENSINITED) invokeArm11Function(ARM11);
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(ARM11);
|
||||
}
|
||||
|
||||
void updateBrightness(u32 brightnessIndex)
|
||||
@@ -126,14 +125,10 @@ void swapFramebuffers(bool isAlternate)
|
||||
invokeArm11Function(ARM11);
|
||||
}
|
||||
|
||||
void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate)
|
||||
void clearScreens(bool isAlternate)
|
||||
{
|
||||
static bool clearTopTmp,
|
||||
clearBottomTmp;
|
||||
static volatile struct fb *fbTmp;
|
||||
clearTopTmp = clearTop;
|
||||
clearBottomTmp = clearBottom;
|
||||
fbTmp = clearAlternate ? &fbs[1] : &fbs[0];
|
||||
fbTmp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
@@ -145,29 +140,21 @@ void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate)
|
||||
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
|
||||
*REGs_PSC1 = (vu32 *)0x10400020;
|
||||
|
||||
if(clearTopTmp)
|
||||
{
|
||||
REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
}
|
||||
REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
if(clearBottomTmp)
|
||||
{
|
||||
REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
}
|
||||
REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
while(!((!clearTopTmp || (REGs_PSC0[3] & 2)) && (!clearBottomTmp || (REGs_PSC1[3] & 2))));
|
||||
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&clearTopTmp, 1);
|
||||
flushDCacheRange(&clearBottomTmp, 1);
|
||||
flushDCacheRange((void *)fbTmp, sizeof(struct fb));
|
||||
flushDCacheRange(&fbTmp, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
@@ -288,13 +275,14 @@ void initScreens(void)
|
||||
|
||||
if(needToSetup)
|
||||
{
|
||||
if(!ARESCREENSINITED)
|
||||
if(!ARESCREENSINITIALIZED)
|
||||
{
|
||||
flushDCacheRange(&configData, sizeof(CfgData));
|
||||
invokeArm11Function(initSequence);
|
||||
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
wait(3ULL);
|
||||
}
|
||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||
|
||||
@@ -303,6 +291,6 @@ void initScreens(void)
|
||||
needToSetup = false;
|
||||
}
|
||||
|
||||
clearScreens(true, true, false);
|
||||
clearScreens(false);
|
||||
swapFramebuffers(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
||||
|
||||
#define ARESCREENSINITED (PDN_GPU_CNT != 1)
|
||||
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
|
||||
|
||||
#define ARM11_STUB_ADDRESS 0x1FFFFFC8
|
||||
#define ARM11_STUB_ADDRESS 0x1FFFFF00
|
||||
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
@@ -53,5 +53,5 @@ extern CfgData configData;
|
||||
void deinitScreens(void);
|
||||
void swapFramebuffers(bool isAlternate);
|
||||
void updateBrightness(u32 brightnessIndex);
|
||||
void clearScreens(bool clearTop, bool clearBottom, bool clearAlternate);
|
||||
void initScreens(void);
|
||||
void clearScreens(bool isAlternate);
|
||||
void initScreens(void);
|
||||
|
||||
@@ -58,7 +58,7 @@ start:
|
||||
@ Set MPU permissions and cache settings
|
||||
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
|
||||
ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
|
||||
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
|
||||
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
|
||||
ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
|
||||
ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
|
||||
ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
|
||||
@@ -91,4 +91,11 @@ start:
|
||||
mov r1, #0x340
|
||||
str r1, [r0]
|
||||
|
||||
@ Clear BSS
|
||||
ldr r0, =__bss_start
|
||||
mov r1, #0
|
||||
ldr r2, =__bss_end
|
||||
sub r2, r0
|
||||
bl memset32
|
||||
|
||||
b main
|
||||
|
||||
@@ -40,14 +40,19 @@ typedef volatile u64 vu64;
|
||||
|
||||
#define BRAHMA_ARM11_ENTRY 0x1FFFFFF8
|
||||
|
||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
||||
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
||||
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
||||
#define CFG_SYSPROT9 (*(vu8 *)0x10000000)
|
||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
||||
#define CFG_TWLUNITINFO (*(vu8 *)0x10010014)
|
||||
#define OTP_DEVCONSOLEID (*(vu64 *)0x10012000)
|
||||
#define OTP_TWLCONSOLEID (*(vu64 *)0x10012100)
|
||||
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
||||
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
||||
|
||||
#define ISN3DS (PDN_MPCORE_CFG == 7)
|
||||
#define ISDEVUNIT (CFG_UNITINFO != 0)
|
||||
#define ISA9LH (!PDN_SPI_CNT)
|
||||
#define ISSIGHAX (!(CFG_SYSPROT9 & 2))
|
||||
#define ISFIRMLAUNCH (launchedFirmTidLow[5] != 0)
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
@@ -101,4 +106,4 @@ typedef enum FirmwareType
|
||||
NATIVE_FIRM1X2X
|
||||
} FirmwareType;
|
||||
|
||||
extern u16 launchedFirmTidLow[8]; //Defined in start.s
|
||||
extern u16 launchedFirmTidLow[8]; //Defined in start.s
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
@@ -27,36 +31,65 @@
|
||||
#include "draw.h"
|
||||
#include "cache.h"
|
||||
|
||||
u32 waitInput(void)
|
||||
static void startChrono(void)
|
||||
{
|
||||
bool pressedKey = false;
|
||||
u32 key;
|
||||
REG_TIMER_CNT(0) = 0; //67MHz
|
||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
||||
|
||||
//Wait for no keys to be pressed
|
||||
while(HID_PAD);
|
||||
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = 0;
|
||||
|
||||
do
|
||||
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
||||
}
|
||||
|
||||
static u64 chrono(void)
|
||||
{
|
||||
u64 res = 0;
|
||||
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
||||
|
||||
res /= (TICKS_PER_SEC / 1000);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 waitInput(bool isMenu)
|
||||
{
|
||||
static u64 dPadDelay = 0ULL;
|
||||
u32 key,
|
||||
oldKey = HID_PAD;
|
||||
|
||||
if(isMenu)
|
||||
{
|
||||
//Wait for a key to be pressed
|
||||
while(!HID_PAD);
|
||||
dPadDelay = dPadDelay > 0ULL ? 87ULL : 143ULL;
|
||||
startChrono();
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
key = HID_PAD;
|
||||
|
||||
//Make sure it's pressed
|
||||
for(u32 i = 0x13000; i > 0; i--)
|
||||
if(!key)
|
||||
{
|
||||
if(key != HID_PAD) break;
|
||||
if(i == 1) pressedKey = true;
|
||||
if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff();
|
||||
oldKey = 0;
|
||||
dPadDelay = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key == oldKey && (!isMenu || (!(key & DPAD_BUTTONS) || chrono() < dPadDelay))) continue;
|
||||
|
||||
//Make sure the key is pressed
|
||||
u32 i;
|
||||
for(i = 0; i < 0x13000 && key == HID_PAD; i++);
|
||||
if(i == 0x13000) break;
|
||||
}
|
||||
while(!pressedKey);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void mcuPowerOff(void)
|
||||
{
|
||||
if(!ISFIRMLAUNCH && ARESCREENSINITED) clearScreens(true, true, false);
|
||||
if(!ISFIRMLAUNCH && ARESCREENSINITIALIZED) clearScreens(false);
|
||||
|
||||
//Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
flushEntireDCache();
|
||||
@@ -65,38 +98,10 @@ void mcuPowerOff(void)
|
||||
while(true);
|
||||
}
|
||||
|
||||
static inline void startChrono(u64 initialTicks)
|
||||
void wait(u64 amount)
|
||||
{
|
||||
REG_TIMER_CNT(0) = 0; //67MHz
|
||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
||||
|
||||
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = (u16)(initialTicks >> (16 * i));
|
||||
|
||||
REG_TIMER_CNT(0) = 0x80; //67MHz; 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)
|
||||
{
|
||||
startChrono(0);
|
||||
|
||||
u64 startingTicks = 0;
|
||||
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
|
||||
|
||||
u64 res;
|
||||
do
|
||||
{
|
||||
res = 0;
|
||||
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
||||
}
|
||||
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
||||
|
||||
stopChrono();
|
||||
startChrono();
|
||||
while(chrono() < amount);
|
||||
}
|
||||
|
||||
void error(const char *message)
|
||||
@@ -109,8 +114,8 @@ void error(const char *message)
|
||||
u32 posY = drawString(message, true, 10, 30, COLOR_WHITE);
|
||||
drawString("Press any button to shutdown", true, 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
waitInput();
|
||||
waitInput(false);
|
||||
}
|
||||
|
||||
mcuPowerOff();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
@@ -28,7 +32,7 @@
|
||||
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
|
||||
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
|
||||
|
||||
u32 waitInput(void);
|
||||
u32 waitInput(bool isMenu);
|
||||
void mcuPowerOff(void);
|
||||
void chrono(u32 seconds);
|
||||
void wait(u64 amount);
|
||||
void error(const char *message);
|
||||
Reference in New Issue
Block a user