Compare commits
391 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f915401dd | ||
|
|
14152b3072 | ||
|
|
8f3cba37b3 | ||
|
|
0853f6f7ad | ||
|
|
ae7a7ba365 | ||
|
|
724af0fdc4 | ||
|
|
550ea2116e | ||
|
|
7952271d61 | ||
|
|
ffaa5790c2 | ||
|
|
934c4bed0b | ||
|
|
6f040caa98 | ||
|
|
50e5c29b1c | ||
|
|
e0b5539b91 | ||
|
|
050f58a3bb | ||
|
|
c739ed8e48 | ||
|
|
a09fc6ebcb | ||
|
|
4367ea6afa | ||
|
|
da0adeb39e | ||
|
|
63160a22a6 | ||
|
|
2bc1927ebd | ||
|
|
66e0cfc185 | ||
|
|
7bd0e4f5b4 | ||
|
|
7271850df2 | ||
|
|
8c79285774 | ||
|
|
56a77ceac1 | ||
|
|
3034420ac2 | ||
|
|
99a157649d | ||
|
|
e6645554f0 | ||
|
|
0f83d1ffaa | ||
|
|
2286eb21a7 | ||
|
|
64c81aa5f8 | ||
|
|
29dcfca608 | ||
|
|
f1cb9630ec | ||
|
|
ebbea57400 | ||
|
|
6016dc14f8 | ||
|
|
dc8e4e5f14 | ||
|
|
72c8212a0e | ||
|
|
2cd2a081d6 | ||
|
|
b44ec544f4 | ||
|
|
063eae7e95 | ||
|
|
2552572904 | ||
|
|
b74dda42a2 | ||
|
|
6e178e2069 | ||
|
|
277d723992 | ||
|
|
2f6afe9932 | ||
|
|
edcc617780 | ||
|
|
5d39242b83 | ||
|
|
ddbe5fd27b | ||
|
|
deb91d1d02 | ||
|
|
63073ea07f | ||
|
|
a331fcd873 | ||
|
|
99654bd5b2 | ||
|
|
f10427287f | ||
|
|
5b6318ee3a | ||
|
|
98cdbe0784 | ||
|
|
e4eb3ae38d | ||
|
|
6686e4add7 | ||
|
|
96a274bf7d | ||
|
|
add17a7994 | ||
|
|
26e404c6a2 | ||
|
|
144de8b328 | ||
|
|
c0226e6fd9 | ||
|
|
57d728a9be | ||
|
|
b2e9f5377b | ||
|
|
d3d315784c | ||
|
|
942a371b6a | ||
|
|
66ffc78f60 | ||
|
|
a9570cef14 | ||
|
|
16bc08f046 | ||
|
|
024335e5cd | ||
|
|
8f32048774 | ||
|
|
33d3dd256d | ||
|
|
fc151f7595 | ||
|
|
9152884815 | ||
|
|
2b4e97bec5 | ||
|
|
a63393504f | ||
|
|
97ae8d2d44 | ||
|
|
6c59728516 | ||
|
|
201fe05a06 | ||
|
|
a78889523f | ||
|
|
5cd1a207c9 | ||
|
|
423f0ca631 | ||
|
|
7612e38d41 | ||
|
|
bf234950cb | ||
|
|
bd992fca15 | ||
|
|
45fee57abd | ||
|
|
a2bca96d47 | ||
|
|
9862256ca7 | ||
|
|
6afc8b3b5c | ||
|
|
9b4b4ec543 | ||
|
|
d412711868 | ||
|
|
0b33551d94 | ||
|
|
9c1b585054 | ||
|
|
fc3a69d9ca | ||
|
|
cce4a6d07f | ||
|
|
b16539408b | ||
|
|
eba56d0f64 | ||
|
|
f2181b1d3e | ||
|
|
c93a97f8d7 | ||
|
|
8fd2525cd1 | ||
|
|
62a70cfdac | ||
|
|
ca0a79fc89 | ||
|
|
104b8e859f | ||
|
|
a99b26ff8c | ||
|
|
9bc62ec12d | ||
|
|
84a6bb772f | ||
|
|
263a5eda56 | ||
|
|
7fb17ce52f | ||
|
|
631fad24c0 | ||
|
|
f1d77fa62a | ||
|
|
3bc247b43b | ||
|
|
3608799dff | ||
|
|
c0f042bc2a | ||
|
|
8982ff259a | ||
|
|
726b06b748 | ||
|
|
0057ab9c5a | ||
|
|
048bf0ee4d | ||
|
|
4da0708b51 | ||
|
|
4c529e3145 | ||
|
|
8ceeca372f | ||
|
|
4326ac9be1 | ||
|
|
697c64abe4 | ||
|
|
7e8cf84c42 | ||
|
|
b6d91375a5 | ||
|
|
61305688fd | ||
|
|
492ae4139f | ||
|
|
a84f393bd5 | ||
|
|
5de54d6f9f | ||
|
|
8fc797120f | ||
|
|
5406d648bc | ||
|
|
a2003fba95 | ||
|
|
a76c15d018 | ||
|
|
ae8caf3d3a | ||
|
|
f221915a95 | ||
|
|
7f93733107 | ||
|
|
e8b9e49f57 | ||
|
|
cb9576b10e | ||
|
|
06fe06f9f1 | ||
|
|
abf7c8e565 | ||
|
|
46227e6763 | ||
|
|
2ffe4a5451 | ||
|
|
18bd4bbcf6 | ||
|
|
8209433696 | ||
|
|
ad9e00acaa | ||
|
|
c96f96258f | ||
|
|
82699f3e00 | ||
|
|
e2d828a4a2 | ||
|
|
92328c6a7e | ||
|
|
3f8ad17e86 | ||
|
|
52999db43a | ||
|
|
760aa99709 | ||
|
|
51c514de84 | ||
|
|
317899b4bf | ||
|
|
4c93d2b1f9 | ||
|
|
71c5404bfe | ||
|
|
9c5248b87a | ||
|
|
83a0293af4 | ||
|
|
84f3eddaf8 | ||
|
|
a5c6b908b6 | ||
|
|
94f0d873df | ||
|
|
d6f66d24fa | ||
|
|
31458e9938 | ||
|
|
dca612ffd7 | ||
|
|
5177308d48 | ||
|
|
59ab44a8c7 | ||
|
|
c711ed6253 | ||
|
|
58c6be17eb | ||
|
|
259bcc686c | ||
|
|
356268eae5 | ||
|
|
2dd64b8a92 | ||
|
|
b5cddedb7d | ||
|
|
7afdc2b3b5 | ||
|
|
60c4956290 | ||
|
|
4c6a2f7ab1 | ||
|
|
76cee0d95b | ||
|
|
7331a919e4 | ||
|
|
27ea6b96c4 | ||
|
|
33238cee54 | ||
|
|
384dd2ad81 | ||
|
|
4885e0b8d8 | ||
|
|
2a84911d3b | ||
|
|
7f672fb417 | ||
|
|
a13fdeecf6 | ||
|
|
74ac76ba84 | ||
|
|
253e031f83 | ||
|
|
ef1ecf859c | ||
|
|
a302ad3bea | ||
|
|
0951260df7 | ||
|
|
b87dadbb72 | ||
|
|
1dd6a9821a | ||
|
|
50a2424001 | ||
|
|
61e5a4444f | ||
|
|
de3eb6ccd7 | ||
|
|
4f8c66b2b7 | ||
|
|
4d9cbc4e19 | ||
|
|
40369d44df | ||
|
|
ee3720f0b7 | ||
|
|
e5dcca1c2b | ||
|
|
ef8438a214 | ||
|
|
dfd699c16b | ||
|
|
a381c2a811 | ||
|
|
e4c87a59d0 | ||
|
|
eef30ceb3c | ||
|
|
76411387ba | ||
|
|
8d5d8d2100 | ||
|
|
802bce12a7 | ||
|
|
a1024c288e | ||
|
|
a4531b01d5 | ||
|
|
d445b20e90 | ||
|
|
24ddf5ca3d | ||
|
|
bb117d3d74 | ||
|
|
c101653077 | ||
|
|
5248b96f8a | ||
|
|
7ab59e420a | ||
|
|
83a849126a | ||
|
|
c9c373f607 | ||
|
|
aa7c2c0009 | ||
|
|
57fc4df86f | ||
|
|
75acdc8a98 | ||
|
|
070f7fcc68 | ||
|
|
4d48238fb1 | ||
|
|
9b304404f7 | ||
|
|
8e5ced8e3c | ||
|
|
95ef379ac5 | ||
|
|
915f9ccb0d | ||
|
|
3709ac301a | ||
|
|
3bc966f84e | ||
|
|
457b4cec13 | ||
|
|
88891ef6cd | ||
|
|
25811e2b52 | ||
|
|
f81c92e35b | ||
|
|
39b2aff627 | ||
|
|
905777466d | ||
|
|
4e21cf4f1c | ||
|
|
eccf9eab93 | ||
|
|
c36ad54bcb | ||
|
|
81e2b7c11c | ||
|
|
18b5cdcddf | ||
|
|
fe31114779 | ||
|
|
df30a2a320 | ||
|
|
cf7fa8ecbd | ||
|
|
389a169443 | ||
|
|
e01802e299 | ||
|
|
709aefba5d | ||
|
|
e4ed713fce | ||
|
|
d3c507b0d4 | ||
|
|
a68e14def3 | ||
|
|
8175642a2a | ||
|
|
8d1befea9e | ||
|
|
e7b8a0ef39 | ||
|
|
be6ee894f9 | ||
|
|
e0e8ed2113 | ||
|
|
c63e46b1a9 | ||
|
|
eb9c74a1ed | ||
|
|
efd83e063e | ||
|
|
ae23a1c84d | ||
|
|
fd1253caac | ||
|
|
a0e8bc1de3 | ||
|
|
004f0652c9 | ||
|
|
d5190cd788 | ||
|
|
2412faf033 | ||
|
|
72caad86cc | ||
|
|
7df9917a00 | ||
|
|
575adcbb9d | ||
|
|
2d6debddb9 | ||
|
|
53d2aac2ae | ||
|
|
96211813e3 | ||
|
|
153bbd6242 | ||
|
|
730e716f0f | ||
|
|
2238293c0f | ||
|
|
29d8e637d8 | ||
|
|
136e0d8974 | ||
|
|
0eb87df84f | ||
|
|
a9db998d84 | ||
|
|
fcb8edffdf | ||
|
|
61684ecb68 | ||
|
|
0ced86b55f | ||
|
|
159c9cb475 | ||
|
|
2943dcb2e9 | ||
|
|
984c3e549c | ||
|
|
edfd63e1f7 | ||
|
|
e593584a47 | ||
|
|
ef60c8ea4c | ||
|
|
e478908dca | ||
|
|
ca587692eb | ||
|
|
f78dd5365c | ||
|
|
f9d6cdccb0 | ||
|
|
35fdd470b3 | ||
|
|
edff11be7b | ||
|
|
bb230de72c | ||
|
|
2d7dde9cf9 | ||
|
|
b77d619873 | ||
|
|
ae1033d975 | ||
|
|
99d28c4f79 | ||
|
|
2424865fa1 | ||
|
|
6a280723f8 | ||
|
|
f85bbfff58 | ||
|
|
d239d82379 | ||
|
|
9017de6082 | ||
|
|
477414a636 | ||
|
|
5fac49447c | ||
|
|
30b3a51309 | ||
|
|
bafba1197e | ||
|
|
2fab0be5e8 | ||
|
|
7ea2a0a278 | ||
|
|
a3ae38520c | ||
|
|
c36fa01651 | ||
|
|
9aeac7af92 | ||
|
|
859944dc8e | ||
|
|
a6dc3c8fc7 | ||
|
|
61c02ed079 | ||
|
|
afc6f51ff2 | ||
|
|
c32eefaa51 | ||
|
|
b6969cf0d1 | ||
|
|
58a33ee6e9 | ||
|
|
050f433046 | ||
|
|
d48f6b62ce | ||
|
|
ffee64c67f | ||
|
|
8cbc535755 | ||
|
|
ca07af2fe9 | ||
|
|
2fe5da97eb | ||
|
|
6ffaeadd1b | ||
|
|
2c10b6bff2 | ||
|
|
76acfd9934 | ||
|
|
06cc4f7172 | ||
|
|
158659e5b0 | ||
|
|
7e46046e3b | ||
|
|
808c4b7361 | ||
|
|
03dc4fc425 | ||
|
|
b4029dcd73 | ||
|
|
1750b256eb | ||
|
|
d00d82ac89 | ||
|
|
edb5a82a89 | ||
|
|
f7552f7c32 | ||
|
|
4483b65b25 | ||
|
|
d2f53626ae | ||
|
|
ac01fe417e | ||
|
|
2fd8c7aace | ||
|
|
b90b138766 | ||
|
|
c3ad7eda08 | ||
|
|
02c6a3c214 | ||
|
|
8dd9c1a1af | ||
|
|
be54052b6d | ||
|
|
9e87679ee2 | ||
|
|
17964f8cd1 | ||
|
|
a63fb971d4 | ||
|
|
4b500349e6 | ||
|
|
8e554e17c9 | ||
|
|
1d77206ae4 | ||
|
|
4340c326dc | ||
|
|
c6cb97ae30 | ||
|
|
9d68c980e6 | ||
|
|
e2596a0a61 | ||
|
|
17d3c6491a | ||
|
|
f55fc421ea | ||
|
|
169b12fc20 | ||
|
|
905f816bbe | ||
|
|
fef48a449a | ||
|
|
95d06c115a | ||
|
|
113059e57c | ||
|
|
408c70b90c | ||
|
|
5b51574ebf | ||
|
|
1e6d7a5aee | ||
|
|
a28b50cee8 | ||
|
|
df112b550b | ||
|
|
85615d1916 | ||
|
|
c6d3158b56 | ||
|
|
4a4de608ec | ||
|
|
e651c3d9cc | ||
|
|
9c12496b30 | ||
|
|
bfc2448662 | ||
|
|
faa04b0309 | ||
|
|
ca1ea7fd6e | ||
|
|
57dc1b09ad | ||
|
|
5a9d0e2569 | ||
|
|
f6d3abbc11 | ||
|
|
041ca8451e | ||
|
|
9ab3a7c451 | ||
|
|
2382e6d82c | ||
|
|
f0e1937eeb | ||
|
|
efd08ff731 | ||
|
|
f9a1f1a79b | ||
|
|
a736e4602a | ||
|
|
5202ba8826 | ||
|
|
0f1bc98bb7 | ||
|
|
d40722af53 | ||
|
|
c9781ab626 | ||
|
|
4cbf4e93e7 | ||
|
|
1f68c2da42 | ||
|
|
d786c292f3 | ||
|
|
ada3e09784 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,12 +1,12 @@
|
|||||||
out
|
out
|
||||||
build
|
build
|
||||||
loader/build
|
loader/build
|
||||||
screeninit/build
|
|
||||||
injector/build
|
injector/build
|
||||||
|
exceptions/arm9/build
|
||||||
|
exceptions/arm11/build
|
||||||
*.bin
|
*.bin
|
||||||
*.3dsx
|
*.3dsx
|
||||||
*.smdh
|
*.smdh
|
||||||
*.o
|
*.o
|
||||||
*.d
|
*.d
|
||||||
*.elf
|
*.elf
|
||||||
*.bat
|
|
||||||
2
CakeBrah
2
CakeBrah
Submodule CakeBrah updated: 42ebe0d0bc...9f7cea77d4
2
CakeHax
2
CakeHax
Submodule CakeHax updated: 6b8fca0b37...5245c7b9dc
105
Makefile
105
Makefile
@@ -12,31 +12,44 @@ LD := arm-none-eabi-ld
|
|||||||
OC := arm-none-eabi-objcopy
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
name := Luma3DS
|
name := Luma3DS
|
||||||
version := $(shell git describe --abbrev=0 --tags)
|
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||||
|
commit := $(shell git rev-parse --short=8 HEAD)
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_patches := patches
|
dir_patches := patches
|
||||||
dir_loader := loader
|
dir_loader := loader
|
||||||
dir_screeninit := screeninit
|
|
||||||
dir_injector := injector
|
dir_injector := injector
|
||||||
|
dir_exceptions := exceptions
|
||||||
|
dir_arm9_exceptions := $(dir_exceptions)/arm9
|
||||||
|
dir_arm11_exceptions := $(dir_exceptions)/arm11
|
||||||
dir_mset := CakeHax
|
dir_mset := CakeHax
|
||||||
dir_ninjhax := CakeBrah
|
dir_ninjhax := CakeBrah
|
||||||
|
dir_menuhax := menuhax
|
||||||
|
dir_pathchanger := pathchanger
|
||||||
dir_build := build
|
dir_build := build
|
||||||
dir_out := out
|
dir_out := out
|
||||||
|
|
||||||
ASFLAGS := -mcpu=arm946e-s
|
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 -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||||
LDFLAGS := -nostartfiles
|
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" --no-print-directory
|
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
|
||||||
|
|
||||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
bundled = $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/injector.h $(dir_build)/loader.h
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEV)),TRUE)
|
||||||
|
CFLAGS += -DDEV
|
||||||
|
bundled += $(dir_build)/k11modulespatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h
|
||||||
|
title := \"$(name) $(revision) (dev) configuration\"
|
||||||
|
else
|
||||||
|
title := \"$(name) $(revision) configuration\"
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: launcher a9lh ninjhax
|
all: launcher a9lh ninjhax menuhax
|
||||||
|
|
||||||
.PHONY: launcher
|
.PHONY: launcher
|
||||||
launcher: $(dir_out)/$(name).dat
|
launcher: $(dir_out)/$(name).dat
|
||||||
@@ -47,25 +60,39 @@ a9lh: $(dir_out)/arm9loaderhax.bin
|
|||||||
.PHONY: ninjhax
|
.PHONY: ninjhax
|
||||||
ninjhax: $(dir_out)/3ds/$(name)
|
ninjhax: $(dir_out)/3ds/$(name)
|
||||||
|
|
||||||
|
.PHONY: menuhax
|
||||||
|
menuhax: $(dir_out)/menuhax/boot.3dsx
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: $(dir_out)/$(name)$(version).7z
|
ifeq ($(strip $(DEV)),TRUE)
|
||||||
|
release: $(dir_out)/$(name)$(revision)-dev.7z
|
||||||
|
else
|
||||||
|
release: $(dir_out)/$(name)$(revision).7z
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||||
@$(MAKE) -C $(dir_loader) clean
|
@$(MAKE) -C $(dir_loader) clean
|
||||||
@$(MAKE) -C $(dir_screeninit) clean
|
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||||
|
@$(MAKE) -C $(dir_arm11_exceptions) clean
|
||||||
@$(MAKE) -C $(dir_injector) clean
|
@$(MAKE) -C $(dir_injector) clean
|
||||||
@rm -rf $(dir_out) $(dir_build)
|
@rm -rf $(dir_out) $(dir_build)
|
||||||
|
|
||||||
$(dir_out):
|
$(dir_out):
|
||||||
@mkdir -p "$(dir_out)/luma/payloads"
|
@mkdir -p "$(dir_out)"
|
||||||
|
|
||||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||||
|
|
||||||
|
$(dir_out)/menuhax/boot.3dsx: $(dir_menuhax)/menuhax.diff $(dir_out)
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@cd $(dir_ninjhax); patch -p1 < ../$(dir_menuhax)/menuhax.diff; $(MAKE) $(FLAGS); git reset --hard
|
||||||
|
@mv $(dir_out)/$(name).3dsx $@
|
||||||
|
@rm $(dir_out)/$(name).smdh
|
||||||
|
|
||||||
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
|
||||||
@cp -a $(dir_build)/main.bin $@
|
@cp -a $(dir_build)/main.bin $@
|
||||||
|
|
||||||
@@ -74,35 +101,63 @@ $(dir_out)/3ds/$(name): $(dir_out)
|
|||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
||||||
@mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
|
@mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
|
||||||
|
|
||||||
$(dir_out)/$(name)$(version).7z: launcher a9lh ninjhax
|
$(dir_out)/pathchanger: $(dir_pathchanger)/pathchanger.py $(dir_pathchanger)/prebuilt $(dir_out)
|
||||||
|
@mkdir -p "$@"
|
||||||
|
@cp $(dir_pathchanger)/pathchanger.py $@
|
||||||
|
@cp -rfT $(dir_pathchanger)/prebuilt $@
|
||||||
|
|
||||||
|
$(dir_out)/$(name)$(revision).7z: all $(dir_out)/pathchanger
|
||||||
@7z a -mx $@ ./$(@D)/*
|
@7z a -mx $@ ./$(@D)/*
|
||||||
|
|
||||||
|
$(dir_out)/$(name)$(revision)-dev.7z: all $(dir_out)/pathchanger
|
||||||
|
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
||||||
|
|
||||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/main.elf: $(objects)
|
$(dir_build)/main.elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
|
$(dir_build)/emunandpatch.h: $(dir_patches)/emunand.s
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@armips $<
|
@armips $<
|
||||||
@armips $(word 2,$^)
|
@bin2c -o $@ -n emunand $(@D)/emunand.bin
|
||||||
@$(MAKE) -C $(dir_injector)
|
|
||||||
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D)
|
$(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
|
||||||
@bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@bin2c -o $@ -n reboot $(@D)/reboot.bin
|
||||||
|
|
||||||
|
$(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin
|
||||||
|
|
||||||
|
$(dir_build)/injector.h: $(dir_injector)/Makefile
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@$(MAKE) -C $(dir_injector) DEV=$(DEV)
|
||||||
|
@bin2c -o $@ -n injector $(@D)/injector.cxi
|
||||||
|
|
||||||
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
||||||
@$(MAKE) -C $(dir_loader)
|
@$(MAKE) -C $(dir_loader)
|
||||||
@mv $(dir_loader)/loader.bin $(@D)
|
|
||||||
@bin2c -o $@ -n loader $(@D)/loader.bin
|
@bin2c -o $@ -n loader $(@D)/loader.bin
|
||||||
|
|
||||||
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
$(dir_build)/k11modulespatch.h: $(dir_patches)/k11modules.s
|
||||||
@$(MAKE) -C $(dir_screeninit)
|
@mkdir -p "$(@D)"
|
||||||
@mv $(dir_screeninit)/screeninit.bin $(@D)
|
@armips $<
|
||||||
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
@bin2c -o $@ -n k11modules $(@D)/k11modules.bin
|
||||||
|
|
||||||
$(dir_build)/memory.o : CFLAGS += -O3
|
$(dir_build)/arm9_exceptions.h: $(dir_arm9_exceptions)/Makefile
|
||||||
$(dir_build)/config.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
|
@$(MAKE) -C $(dir_arm9_exceptions)
|
||||||
|
@bin2c -o $@ -n arm9_exceptions $(@D)/arm9_exceptions.bin
|
||||||
|
|
||||||
|
$(dir_build)/arm11_exceptions.h: $(dir_arm11_exceptions)/Makefile
|
||||||
|
@$(MAKE) -C $(dir_arm11_exceptions)
|
||||||
|
@bin2c -o $@ -n arm11_exceptions $(@D)/arm11_exceptions.bin
|
||||||
|
|
||||||
|
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||||
|
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="$(title)"
|
||||||
|
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@@ -111,12 +166,4 @@ $(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
|||||||
$(dir_build)/%.o: $(dir_source)/%.s
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
|
||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
|
||||||
include $(call rwildcard, $(dir_build), *.d)
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -1,16 +1,37 @@
|
|||||||
# Luma3DS
|
# Luma3DS
|
||||||
*Noob-proof (N)3DS "Custom Firmware"*
|
*Noob-proof (N)3DS "Custom Firmware"*
|
||||||
|
|
||||||
**Compiling:**
|
## What it is
|
||||||
|
|
||||||
You'll need armips, [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips for Windows.
|
**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).
|
||||||
Then, just run "make" and everything should work!
|
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
|
||||||
You can find the compiled files in the 'out' folder.
|
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.
|
||||||
|
|
||||||
**Setup / Usage / Features:**
|
---
|
||||||
|
|
||||||
|
## Compiling
|
||||||
|
|
||||||
|
First you need to clone the repository recursively with: `git clone --recursive https://github.com/AuroraWright/Luma3DS.git`
|
||||||
|
To compile, you'll need [armips](https://github.com/Kingcom/armips), [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH.
|
||||||
|
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!).
|
||||||
|
Finally just run `make` (for the regular version) or `make DEV=TRUE` (for the dev version) and everything should work!
|
||||||
|
You can find the compiled files in the `out` folder.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Setup / Usage / Features
|
||||||
|
|
||||||
See https://github.com/AuroraWright/Luma3DS/wiki
|
See https://github.com/AuroraWright/Luma3DS/wiki
|
||||||
|
|
||||||
**Credits:**
|
---
|
||||||
|
|
||||||
See https://github.com/AuroraWright/Luma3DS/wiki/Credits
|
## Credits
|
||||||
|
|
||||||
|
See https://github.com/AuroraWright/Luma3DS/wiki/Credits
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
This software is licensed under the terms of the GPLv3.
|
||||||
|
You can find a copy of the license in the LICENSE.txt file.
|
||||||
|
|||||||
47
exceptions/arm11/Makefile
Normal file
47
exceptions/arm11/Makefile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
|
CC := arm-none-eabi-gcc
|
||||||
|
AS := arm-none-eabi-as
|
||||||
|
LD := arm-none-eabi-ld
|
||||||
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
|
name := arm11_exceptions
|
||||||
|
|
||||||
|
dir_source := source
|
||||||
|
dir_build := 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
|
||||||
|
LDFLAGS := -nostdlib
|
||||||
|
|
||||||
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: ../../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
|
../../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
3
screeninit/linker.ld → exceptions/arm11/linker.ld
Executable file → Normal file
3
screeninit/linker.ld → exceptions/arm11/linker.ld
Executable file → Normal file
@@ -1,7 +1,7 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x24F03000;
|
. = 0;
|
||||||
.text.start : { *(.text.start) }
|
.text.start : { *(.text.start) }
|
||||||
.text : { *(.text) }
|
.text : { *(.text) }
|
||||||
.data : { *(.data) }
|
.data : { *(.data) }
|
||||||
@@ -9,4 +9,3 @@ SECTIONS
|
|||||||
.rodata : { *(.rodata) }
|
.rodata : { *(.rodata) }
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
48
exceptions/arm11/source/handlers.h
Normal file
48
exceptions/arm11/source/handlers.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
u32 magic[2];
|
||||||
|
u16 versionMinor, versionMajor;
|
||||||
|
|
||||||
|
u16 processor, core;
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
u32 totalSize;
|
||||||
|
u32 registerDumpSize;
|
||||||
|
u32 codeDumpSize;
|
||||||
|
u32 stackDumpSize;
|
||||||
|
u32 additionalDataSize;
|
||||||
|
} ExceptionDumpHeader;
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) mcuReboot(void);
|
||||||
|
void cleanInvalidateDCacheAndDMB(void);
|
||||||
|
bool cannotAccessVA(const void *address);
|
||||||
|
void FIQHandler(void);
|
||||||
|
void undefinedInstructionHandler(void);
|
||||||
|
void dataAbortHandler(void);
|
||||||
|
void prefetchAbortHandler(void);
|
||||||
150
exceptions/arm11/source/handlers.s
Normal file
150
exceptions/arm11/source/handlers.s
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.macro GEN_HANDLER name
|
||||||
|
.global \name
|
||||||
|
.type \name, %function
|
||||||
|
\name:
|
||||||
|
ldr sp, =#0xffff3000
|
||||||
|
stmfd sp!, {r0-r7}
|
||||||
|
mov r1, #\@ @ macro expansion counter
|
||||||
|
b _commonHandler
|
||||||
|
|
||||||
|
.size \name, . - \name
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global _commonHandler
|
||||||
|
.type _commonHandler, %function
|
||||||
|
_commonHandler:
|
||||||
|
clrex
|
||||||
|
cpsid aif
|
||||||
|
mrs r2, spsr
|
||||||
|
mov r6, sp
|
||||||
|
mrs r3, cpsr
|
||||||
|
|
||||||
|
tst r2, #0x20
|
||||||
|
bne noFPUInitNorSvcBreak
|
||||||
|
sub r0, lr, #4
|
||||||
|
stmfd sp!, {lr}
|
||||||
|
bl cannotAccessVA
|
||||||
|
ldmfd sp!, {lr}
|
||||||
|
cmp r0, #0
|
||||||
|
bne noFPUInitNorSvcBreak
|
||||||
|
ldr r4, [lr, #-4]
|
||||||
|
cmp r1, #1
|
||||||
|
bne noFPUInit
|
||||||
|
|
||||||
|
lsl r4, #4
|
||||||
|
sub r4, #0xc0000000
|
||||||
|
cmp r4, #0x30000000
|
||||||
|
bcs noFPUInitNorSvcBreak
|
||||||
|
fmrx r0, fpexc
|
||||||
|
tst r0, #0x40000000
|
||||||
|
bne noFPUInitNorSvcBreak
|
||||||
|
|
||||||
|
sub lr, #4
|
||||||
|
srsfd sp!, #0x13
|
||||||
|
ldmfd sp!, {r0-r7} @ restore context
|
||||||
|
cps #0x13 @ FPU init
|
||||||
|
stmfd sp, {r0-r3, r11-lr}^
|
||||||
|
sub sp, #0x20
|
||||||
|
bl . @ will be replaced
|
||||||
|
ldmfd sp, {r0-r3, r11-lr}^
|
||||||
|
add sp, #0x20
|
||||||
|
rfefd sp!
|
||||||
|
|
||||||
|
noFPUInit:
|
||||||
|
cmp r1, #2
|
||||||
|
bne noFPUInitNorSvcBreak
|
||||||
|
ldr r5, =#0xe12fff7f
|
||||||
|
cmp r4, r5
|
||||||
|
bne noFPUInitNorSvcBreak
|
||||||
|
cps #0x13 @ switch to supervisor mode
|
||||||
|
cmp r10, #0
|
||||||
|
addne sp, #0x28
|
||||||
|
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
|
||||||
|
ldr r4, [sp, #0x18]
|
||||||
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
|
tst r2, #0x20
|
||||||
|
addne lr, r4, #2 @ adjust address for later
|
||||||
|
moveq lr, r4
|
||||||
|
|
||||||
|
noFPUInitNorSvcBreak:
|
||||||
|
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||||
|
moveq r4, #0xf @ usr => sys
|
||||||
|
bic r5, r3, #0xf
|
||||||
|
orr r5, r4
|
||||||
|
msr cpsr_c, r5 @ change processor mode
|
||||||
|
stmfd r6!, {r8-lr}
|
||||||
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
|
mov sp, r6
|
||||||
|
|
||||||
|
stmfd sp!, {r2,lr}
|
||||||
|
|
||||||
|
mrc p15,0,r4,c5,c0,0 @ dfsr
|
||||||
|
mrc p15,0,r5,c5,c0,1 @ ifsr
|
||||||
|
mrc p15,0,r6,c6,c0,0 @ far
|
||||||
|
fmrx r7, fpexc
|
||||||
|
fmrx r8, fpinst
|
||||||
|
fmrx r9, fpinst2
|
||||||
|
|
||||||
|
stmfd sp!, {r4-r9} @ it's a bit of a mess, but we will fix that later
|
||||||
|
@ order of saved regs now: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc + (2/4/8), r8-r14, r0-r7
|
||||||
|
|
||||||
|
bic r3, #(1<<31)
|
||||||
|
fmxr fpexc, r3 @ clear the VFP11 exception flag (if it's set)
|
||||||
|
|
||||||
|
mov r0, sp
|
||||||
|
mrc p15,0,r2,c0,c0,5 @ CPU ID register
|
||||||
|
|
||||||
|
b mainHandler
|
||||||
|
|
||||||
|
GEN_HANDLER FIQHandler
|
||||||
|
GEN_HANDLER undefinedInstructionHandler
|
||||||
|
GEN_HANDLER prefetchAbortHandler
|
||||||
|
GEN_HANDLER dataAbortHandler
|
||||||
|
|
||||||
|
.global mcuReboot
|
||||||
|
.type mcuReboot, %function
|
||||||
|
mcuReboot:
|
||||||
|
b . @ will be replaced
|
||||||
|
|
||||||
|
.global cleanInvalidateDCacheAndDMB
|
||||||
|
.type cleanInvalidateDCacheAndDMB, %function
|
||||||
|
cleanInvalidateDCacheAndDMB:
|
||||||
|
mov r0, #0
|
||||||
|
mcr p15,0,r0,c7,c14,0 @ Clean and Invalidate Entire Data Cache
|
||||||
|
mcr p15,0,r0,c7,c10,4 @ Drain Memory Barrier
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global cannotAccessVA
|
||||||
|
.type cannotAccessVA, %function
|
||||||
|
cannotAccessVA:
|
||||||
|
@ Thanks yellows8 for the hint
|
||||||
|
lsr r0, #12
|
||||||
|
lsl r0, #12
|
||||||
|
mcr p15,0,r0,c7,c8,0 @ VA to PA translation with privileged read permission check
|
||||||
|
mrc p15,0,r0,c7,c4,0 @ read PA register
|
||||||
|
and r0, #1 @ failure bit
|
||||||
|
bx lr
|
||||||
110
exceptions/arm11/source/mainHandler.c
Normal file
110
exceptions/arm11/source/mainHandler.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "handlers.h"
|
||||||
|
|
||||||
|
#define FINAL_BUFFER 0xE5000000 //0x25000000
|
||||||
|
|
||||||
|
#define REG_DUMP_SIZE 4 * 23
|
||||||
|
#define CODE_DUMP_SIZE 48
|
||||||
|
|
||||||
|
#define CODESET_OFFSET 0xBEEFBEEF
|
||||||
|
|
||||||
|
static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment)
|
||||||
|
{
|
||||||
|
u8 *out = (u8 *)dst;
|
||||||
|
const u8 *in = (const u8 *)src;
|
||||||
|
|
||||||
|
if(((u32)src & (alignment - 1)) != 0 || cannotAccessVA(src) || (size != 0 && cannotAccessVA((u8 *)src + size - 1)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size; i++)
|
||||||
|
*out++ = *in++;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId)
|
||||||
|
{
|
||||||
|
ExceptionDumpHeader dumpHeader;
|
||||||
|
|
||||||
|
u32 registerDump[REG_DUMP_SIZE / 4];
|
||||||
|
u8 codeDump[CODE_DUMP_SIZE];
|
||||||
|
u8 *final = (u8 *)FINAL_BUFFER;
|
||||||
|
|
||||||
|
while(*(vu32 *)final == 0xDEADC0DE && *((vu32 *)final + 1) == 0xDEADCAFE);
|
||||||
|
|
||||||
|
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||||
|
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||||
|
dumpHeader.versionMajor = 1;
|
||||||
|
dumpHeader.versionMinor = 2;
|
||||||
|
|
||||||
|
dumpHeader.processor = 11;
|
||||||
|
dumpHeader.core = cpuId & 0xF;
|
||||||
|
dumpHeader.type = type;
|
||||||
|
|
||||||
|
dumpHeader.registerDumpSize = REG_DUMP_SIZE;
|
||||||
|
dumpHeader.codeDumpSize = CODE_DUMP_SIZE;
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
registerDump[15] = pc;
|
||||||
|
registerDump[16] = cpsr;
|
||||||
|
for(u32 i = 0; i < 6; i++) registerDump[17 + i] = regs[i];
|
||||||
|
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[8 + i];
|
||||||
|
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[15 + i];
|
||||||
|
|
||||||
|
//Dump code
|
||||||
|
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||||
|
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4);
|
||||||
|
|
||||||
|
//Copy register dump and code dump
|
||||||
|
final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||||
|
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||||
|
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||||
|
|
||||||
|
//Dump stack in place
|
||||||
|
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||||
|
final += dumpHeader.stackDumpSize;
|
||||||
|
|
||||||
|
if(!cannotAccessVA((u8 *)0xFFFF9004))
|
||||||
|
{
|
||||||
|
vu64 *additionalData = (vu64 *)final;
|
||||||
|
dumpHeader.additionalDataSize = 16;
|
||||||
|
vu8 *currentKCodeSet = *(vu8 **)(*(vu8 **)0xFFFF9004 + CODESET_OFFSET); //currentKProcess + CodeSet
|
||||||
|
|
||||||
|
additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name
|
||||||
|
additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID
|
||||||
|
}
|
||||||
|
else dumpHeader.additionalDataSize = 0;
|
||||||
|
|
||||||
|
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||||
|
|
||||||
|
//Copy header (actually optimized by the compiler)
|
||||||
|
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
|
||||||
|
|
||||||
|
cleanInvalidateDCacheAndDMB();
|
||||||
|
mcuReboot(); //Also contains DCache-cleaning code
|
||||||
|
}
|
||||||
31
exceptions/arm11/source/start.s
Normal file
31
exceptions/arm11/source/start.s
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.section .text.start
|
||||||
|
.align 4
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
.word FIQHandler
|
||||||
|
.word undefinedInstructionHandler
|
||||||
|
.word prefetchAbortHandler
|
||||||
|
.word dataAbortHandler
|
||||||
37
exceptions/arm11/source/types.h
Normal file
37
exceptions/arm11/source/types.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
//Common data types
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef volatile u8 vu8;
|
||||||
|
typedef volatile u16 vu16;
|
||||||
|
typedef volatile u32 vu32;
|
||||||
|
typedef volatile u64 vu64;
|
||||||
10
screeninit/Makefile → exceptions/arm9/Makefile
Executable file → Normal file
10
screeninit/Makefile → exceptions/arm9/Makefile
Executable file → Normal file
@@ -11,12 +11,12 @@ AS := arm-none-eabi-as
|
|||||||
LD := arm-none-eabi-ld
|
LD := arm-none-eabi-ld
|
||||||
OC := arm-none-eabi-objcopy
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
name := $(shell basename $(CURDIR))
|
name := arm9_exceptions
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_build := build
|
dir_build := build
|
||||||
|
|
||||||
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
|
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 -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||||
LDFLAGS := -nostdlib
|
LDFLAGS := -nostdlib
|
||||||
|
|
||||||
@@ -25,17 +25,17 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).bin
|
all: ../../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).bin: $(dir_build)/$(name).elf
|
../../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
11
exceptions/arm9/linker.ld
Normal file
11
exceptions/arm9/linker.ld
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x01FF7FE0;
|
||||||
|
.text.start : { *(.text.start) }
|
||||||
|
.text : { *(.text) }
|
||||||
|
.data : { *(.data) }
|
||||||
|
.bss : { *(.bss COMMON) }
|
||||||
|
.rodata : { *(.rodata) }
|
||||||
|
. = ALIGN(4);
|
||||||
|
}
|
||||||
46
exceptions/arm9/source/handlers.h
Normal file
46
exceptions/arm9/source/handlers.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
u32 magic[2];
|
||||||
|
u16 versionMinor, versionMajor;
|
||||||
|
|
||||||
|
u16 processor, core;
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
u32 totalSize;
|
||||||
|
u32 registerDumpSize;
|
||||||
|
u32 codeDumpSize;
|
||||||
|
u32 stackDumpSize;
|
||||||
|
u32 additionalDataSize;
|
||||||
|
} ExceptionDumpHeader;
|
||||||
|
|
||||||
|
u32 readMPUConfig(u32 *regionSettings);
|
||||||
|
void FIQHandler(void);
|
||||||
|
void undefinedInstructionHandler(void);
|
||||||
|
void dataAbortHandler(void);
|
||||||
|
void prefetchAbortHandler(void);
|
||||||
108
exceptions/arm9/source/handlers.s
Normal file
108
exceptions/arm9/source/handlers.s
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.macro GEN_HANDLER name
|
||||||
|
.global \name
|
||||||
|
.type \name, %function
|
||||||
|
\name:
|
||||||
|
ldr sp, =#0x02000000 @ We make the (full descending) stack point to the end of ITCM for our exception handlers.
|
||||||
|
@ It doesn't matter if we're overwriting stuff here, since we're going to reboot.
|
||||||
|
|
||||||
|
stmfd sp!, {r0-r7} @ FIQ has its own r8-r14 regs
|
||||||
|
ldr r1, =\@ @ macro expansion counter
|
||||||
|
b _commonHandler
|
||||||
|
|
||||||
|
.size \name, . - \name
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global _commonHandler
|
||||||
|
.type _commonHandler, %function
|
||||||
|
_commonHandler:
|
||||||
|
mrs r2, spsr
|
||||||
|
mov r6, sp
|
||||||
|
mrs r3, cpsr
|
||||||
|
|
||||||
|
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11)
|
||||||
|
msr cpsr_cx, r3
|
||||||
|
|
||||||
|
tst r2, #0x20
|
||||||
|
bne noSvcBreak
|
||||||
|
cmp r1, #2
|
||||||
|
bne noSvcBreak
|
||||||
|
|
||||||
|
sub r0, lr, #4 @ calling cannotAccessAddress cause more problems that it actually solves... (I've to save a lot of regs and that's a pain tbh)
|
||||||
|
lsr r0, #20 @ we'll just do some address checks (to see if it's in ARM9 internal memory)
|
||||||
|
cmp r0, #0x80
|
||||||
|
bne noSvcBreak
|
||||||
|
ldr r4, [lr, #-4]
|
||||||
|
ldr r5, =#0xe12fff7f
|
||||||
|
cmp r4, r5
|
||||||
|
bne noSvcBreak
|
||||||
|
bic r5, r3, #0xf
|
||||||
|
orr r5, #0x3
|
||||||
|
msr cpsr_c, r5 @ switch to supervisor mode
|
||||||
|
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
|
||||||
|
ldr r4, [sp, #0x18]
|
||||||
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
|
tst r2, #0x20
|
||||||
|
addne lr, r4, #2 @ adjust address for later
|
||||||
|
moveq lr, r4
|
||||||
|
|
||||||
|
noSvcBreak:
|
||||||
|
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||||
|
moveq r4, #0xf @ usr => sys
|
||||||
|
bic r5, r3, #0xf
|
||||||
|
orr r5, r4
|
||||||
|
msr cpsr_c, r5 @ change processor mode
|
||||||
|
stmfd r6!, {r8-lr}
|
||||||
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
|
mov sp, r6
|
||||||
|
|
||||||
|
stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later
|
||||||
|
@ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7
|
||||||
|
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
b mainHandler
|
||||||
|
|
||||||
|
GEN_HANDLER FIQHandler
|
||||||
|
GEN_HANDLER undefinedInstructionHandler
|
||||||
|
GEN_HANDLER prefetchAbortHandler
|
||||||
|
GEN_HANDLER dataAbortHandler
|
||||||
|
|
||||||
|
.global readMPUConfig
|
||||||
|
.type readMPUConfig, %function
|
||||||
|
readMPUConfig:
|
||||||
|
stmfd sp!, {r4-r8, lr}
|
||||||
|
mrc p15,0,r1,c6,c0,0
|
||||||
|
mrc p15,0,r2,c6,c1,0
|
||||||
|
mrc p15,0,r3,c6,c2,0
|
||||||
|
mrc p15,0,r4,c6,c3,0
|
||||||
|
mrc p15,0,r5,c6,c4,0
|
||||||
|
mrc p15,0,r6,c6,c5,0
|
||||||
|
mrc p15,0,r7,c6,c6,0
|
||||||
|
mrc p15,0,r8,c6,c7,0
|
||||||
|
stmia r0, {r1-r8}
|
||||||
|
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
||||||
|
ldmfd sp!, {r4-r8, pc}
|
||||||
139
exceptions/arm9/source/i2c.c
Normal file
139
exceptions/arm9/source/i2c.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thanks to the everyone who contributed in the development of this file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
||||||
|
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
|
||||||
|
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
|
||||||
|
{1, 0x2E}, {1, 0x40}, {1, 0x44},
|
||||||
|
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
|
||||||
|
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u8 i2cGetDeviceBusId(u8 device_id)
|
||||||
|
{
|
||||||
|
return dev_data[device_id].bus_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
|
||||||
|
{
|
||||||
|
return dev_data[device_id].reg_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static vu8 *reg_data_addrs[] = {
|
||||||
|
(vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
|
||||||
|
(vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
|
||||||
|
(vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline vu8 *i2cGetDataReg(u8 bus_id)
|
||||||
|
{
|
||||||
|
return reg_data_addrs[bus_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static vu8 *reg_cnt_addrs[] = {
|
||||||
|
(vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
|
||||||
|
(vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
|
||||||
|
(vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline vu8 *i2cGetCntReg(u8 bus_id)
|
||||||
|
{
|
||||||
|
return reg_cnt_addrs[bus_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static inline void i2cWaitBusy(u8 bus_id)
|
||||||
|
{
|
||||||
|
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool i2cGetResult(u8 bus_id)
|
||||||
|
{
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
|
||||||
|
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2cStop(u8 bus_id, u8 arg0)
|
||||||
|
{
|
||||||
|
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool i2cSelectDevice(u8 bus_id, u8 dev_reg)
|
||||||
|
{
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
*i2cGetDataReg(bus_id) = dev_reg;
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC2;
|
||||||
|
|
||||||
|
return i2cGetResult(bus_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool i2cSelectRegister(u8 bus_id, u8 reg)
|
||||||
|
{
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
*i2cGetDataReg(bus_id) = reg;
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC0;
|
||||||
|
|
||||||
|
return i2cGetResult(bus_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||||
|
{
|
||||||
|
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||||
|
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||||
|
{
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
*i2cGetDataReg(bus_id) = data;
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC1;
|
||||||
|
i2cStop(bus_id, 0);
|
||||||
|
|
||||||
|
if(i2cGetResult(bus_id)) return true;
|
||||||
|
}
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC5;
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
44
exceptions/arm9/source/i2c.h
Normal file
44
exceptions/arm9/source/i2c.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thanks to the everyone who contributed in the development of this file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define I2C1_REG_OFF 0x10161000
|
||||||
|
#define I2C2_REG_OFF 0x10144000
|
||||||
|
#define I2C3_REG_OFF 0x10148000
|
||||||
|
|
||||||
|
#define I2C_REG_DATA 0
|
||||||
|
#define I2C_REG_CNT 1
|
||||||
|
#define I2C_REG_CNTEX 2
|
||||||
|
#define I2C_REG_SCL 4
|
||||||
|
|
||||||
|
#define I2C_DEV_MCU 3
|
||||||
|
#define I2C_DEV_GYRO 10
|
||||||
|
#define I2C_DEV_IR 13
|
||||||
|
|
||||||
|
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
||||||
118
exceptions/arm9/source/mainHandler.c
Normal file
118
exceptions/arm9/source/mainHandler.c
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
|
||||||
|
#define FINAL_BUFFER 0x25000000
|
||||||
|
|
||||||
|
#define REG_DUMP_SIZE 4 * 17
|
||||||
|
#define CODE_DUMP_SIZE 48
|
||||||
|
|
||||||
|
bool cannotAccessAddress(const void *address)
|
||||||
|
{
|
||||||
|
u32 regionSettings[8];
|
||||||
|
u32 addr = (u32)address;
|
||||||
|
|
||||||
|
u32 dataAccessPermissions = readMPUConfig(regionSettings);
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
|
||||||
|
continue; //No access / region not enabled
|
||||||
|
|
||||||
|
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
|
||||||
|
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
|
||||||
|
|
||||||
|
if(addr >= regionAddrBase && addr < regionAddrBase + regionSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dataAccessPermissions >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment)
|
||||||
|
{
|
||||||
|
u8 *out = (u8 *)dst;
|
||||||
|
const u8 *in = (const u8 *)src;
|
||||||
|
|
||||||
|
if(((u32)src & (alignment - 1)) != 0 || cannotAccessAddress(src) || (size != 0 && cannotAccessAddress((u8 *)src + size - 1)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size; i++)
|
||||||
|
*out++ = *in++;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type)
|
||||||
|
{
|
||||||
|
ExceptionDumpHeader dumpHeader;
|
||||||
|
|
||||||
|
u32 registerDump[REG_DUMP_SIZE / 4];
|
||||||
|
u8 codeDump[CODE_DUMP_SIZE];
|
||||||
|
|
||||||
|
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||||
|
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||||
|
dumpHeader.versionMajor = 1;
|
||||||
|
dumpHeader.versionMinor = 2;
|
||||||
|
|
||||||
|
dumpHeader.processor = 9;
|
||||||
|
dumpHeader.core = 0;
|
||||||
|
dumpHeader.type = type;
|
||||||
|
|
||||||
|
dumpHeader.registerDumpSize = REG_DUMP_SIZE;
|
||||||
|
dumpHeader.codeDumpSize = CODE_DUMP_SIZE;
|
||||||
|
dumpHeader.additionalDataSize = 0;
|
||||||
|
|
||||||
|
//Dump registers
|
||||||
|
//Current order of saved regs: cpsr, pc, r8-r14, r0-r7
|
||||||
|
u32 cpsr = regs[0];
|
||||||
|
u32 pc = regs[1] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||||
|
|
||||||
|
registerDump[15] = pc;
|
||||||
|
registerDump[16] = cpsr;
|
||||||
|
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i];
|
||||||
|
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
||||||
|
|
||||||
|
//Dump code
|
||||||
|
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||||
|
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4);
|
||||||
|
|
||||||
|
//Copy register dump and code dump
|
||||||
|
u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||||
|
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||||
|
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||||
|
|
||||||
|
//Dump stack in place
|
||||||
|
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||||
|
|
||||||
|
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||||
|
|
||||||
|
//Copy header (actually optimized by the compiler)
|
||||||
|
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
|
||||||
|
|
||||||
|
((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
31
exceptions/arm9/source/start.s
Normal file
31
exceptions/arm9/source/start.s
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.section .text.start
|
||||||
|
.align 4
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
.word FIQHandler
|
||||||
|
.word undefinedInstructionHandler
|
||||||
|
.word prefetchAbortHandler
|
||||||
|
.word dataAbortHandler
|
||||||
37
exceptions/arm9/source/types.h
Normal file
37
exceptions/arm9/source/types.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
//Common data types
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef volatile u8 vu8;
|
||||||
|
typedef volatile u16 vu16;
|
||||||
|
typedef volatile u32 vu32;
|
||||||
|
typedef volatile u64 vu64;
|
||||||
147
exceptions/exception_dump_parser.py
Normal file
147
exceptions/exception_dump_parser.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Requires Python >= 3.2 or >= 2.7
|
||||||
|
|
||||||
|
# This file is part of Luma3DS
|
||||||
|
# Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
# reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
# Notices displayed by works containing it.
|
||||||
|
|
||||||
|
__author__ = "TuxSH"
|
||||||
|
__copyright__ = "Copyright (c) 2016 TuxSH"
|
||||||
|
__license__ = "GPLv3"
|
||||||
|
__version__ = "v1.0"
|
||||||
|
|
||||||
|
"""
|
||||||
|
Parses Luma3DS exception dumps
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from struct import unpack_from
|
||||||
|
|
||||||
|
# Source of hexdump: https://gist.github.com/ImmortalPC/c340564823f283fe530b
|
||||||
|
# Credits for hexdump go to the original authors
|
||||||
|
# Slightly edited by TuxSH
|
||||||
|
|
||||||
|
def hexdump(addr, src, length=16, sep='.' ):
|
||||||
|
'''
|
||||||
|
@brief Return {src} in hex dump.
|
||||||
|
@param[in] length {Int} Nb Bytes by row.
|
||||||
|
@param[in] sep {Char} For the text part, {sep} will be used for non ASCII char.
|
||||||
|
@return {Str} The hexdump
|
||||||
|
@note Full support for python2 and python3 !
|
||||||
|
'''
|
||||||
|
result = []
|
||||||
|
|
||||||
|
# Python3 support
|
||||||
|
try:
|
||||||
|
xrange(0,1)
|
||||||
|
except NameError:
|
||||||
|
xrange = range
|
||||||
|
|
||||||
|
for i in xrange(0, len(src), length):
|
||||||
|
subSrc = src[i:i+length]
|
||||||
|
hexa = ''
|
||||||
|
isMiddle = False
|
||||||
|
for h in xrange(0,len(subSrc)):
|
||||||
|
if h == length/2:
|
||||||
|
hexa += ' '
|
||||||
|
h = subSrc[h]
|
||||||
|
if not isinstance(h, int):
|
||||||
|
h = ord(h)
|
||||||
|
h = hex(h).replace('0x','')
|
||||||
|
if len(h) == 1:
|
||||||
|
h = '0'+h
|
||||||
|
hexa += h+' '
|
||||||
|
hexa = hexa.strip(' ')
|
||||||
|
text = ''
|
||||||
|
for c in subSrc:
|
||||||
|
if not isinstance(c, int):
|
||||||
|
c = ord(c)
|
||||||
|
if 0x20 <= c < 0x7F:
|
||||||
|
text += chr(c)
|
||||||
|
else:
|
||||||
|
text += sep
|
||||||
|
result.append(('%08X: %-'+str(length*(2+1)+1)+'s |%s|') % (addr + i, hexa, text))
|
||||||
|
|
||||||
|
return '\n'.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def makeRegisterLine(A, rA, B, rB):
|
||||||
|
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
|
||||||
|
|
||||||
|
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
|
||||||
|
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
|
||||||
|
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
|
||||||
|
parser.add_argument("filename")
|
||||||
|
args = parser.parse_args()
|
||||||
|
data = b""
|
||||||
|
with open(args.filename, "rb") as f: data = f.read()
|
||||||
|
if unpack_from("<2I", data) != (0xdeadc0de, 0xdeadcafe):
|
||||||
|
raise SystemExit("Invalid file format")
|
||||||
|
|
||||||
|
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
|
||||||
|
nbRegisters //= 4
|
||||||
|
|
||||||
|
if version < (1 << 16) | 2:
|
||||||
|
raise SystemExit("Incompatible format version, please use the appropriate parser.")
|
||||||
|
|
||||||
|
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
|
||||||
|
codeDump = data[40 + 4 * nbRegisters : 40 + 4 * nbRegisters + codeDumpSize]
|
||||||
|
stackOffset = 40 + 4 * nbRegisters + codeDumpSize
|
||||||
|
stackDump = data[stackOffset : stackOffset + stackDumpSize]
|
||||||
|
addtionalDataOffset = stackOffset + stackDumpSize
|
||||||
|
additionalData = data[addtionalDataOffset : addtionalDataOffset + additionalDataSize]
|
||||||
|
|
||||||
|
if processor == 9: print("Processor: ARM9")
|
||||||
|
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||||
|
|
||||||
|
typeDetailsStr = ""
|
||||||
|
if exceptionType == 2:
|
||||||
|
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
|
||||||
|
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||||
|
if instr == 0xe12fff7e:
|
||||||
|
typeDetailsStr = " (kernel panic)"
|
||||||
|
elif instr == 0xef00003c:
|
||||||
|
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||||
|
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
|
||||||
|
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||||
|
if instr == 0xdf3c:
|
||||||
|
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||||
|
|
||||||
|
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
||||||
|
typeDetailsStr = " (VFP exception)"
|
||||||
|
|
||||||
|
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
|
||||||
|
if additionalDataSize != 0:
|
||||||
|
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
|
||||||
|
|
||||||
|
print("\nRegister dump:\n")
|
||||||
|
for i in range(0, nbRegisters - (nbRegisters % 2), 2):
|
||||||
|
if i == 16: print("")
|
||||||
|
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
|
||||||
|
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
|
||||||
|
|
||||||
|
print("\nCode dump:\n")
|
||||||
|
print(hexdump(registers[15] - codeDumpSize + (4 if (registers[16] & 0x20 == 0) else 2), codeDump))
|
||||||
|
|
||||||
|
print("\nStack dump:\n")
|
||||||
|
print(hexdump(registers[13], stackDump))
|
||||||
|
|
||||||
@@ -22,30 +22,38 @@ LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
|||||||
|
|
||||||
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
|
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
|
||||||
|
|
||||||
ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
|
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
|
||||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
|
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
|
||||||
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
|
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
|
||||||
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ARCH)
|
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ASFLAGS)
|
||||||
|
|
||||||
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.c))
|
$(call rwildcard, $(dir_source), *.s *.c))
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEV)),TRUE)
|
||||||
|
CFLAGS += -DDEV
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).cxi
|
all: ../$(dir_build)/$(name).cxi
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).cxi: $(dir_build)/$(name).elf
|
../$(dir_build)/$(name).cxi: $(dir_build)/$(name).elf
|
||||||
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
||||||
|
|
||||||
$(dir_build)/memory.o : CFLAGS += -O3
|
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
include $(call rwildcard, $(dir_build), *.d)
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
|
|||||||
19
injector/source/CFWInfo.h
Normal file
19
injector/source/CFWInfo.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
u8 versionMajor;
|
||||||
|
u8 versionMinor;
|
||||||
|
u8 versionBuild;
|
||||||
|
u8 flags; /* bit 0: dev branch; bit 1: is release */
|
||||||
|
|
||||||
|
u32 commitHash;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CFWInfo;
|
||||||
|
|
||||||
|
u32 svcGetCFWInfo(CFWInfo *info);
|
||||||
9
injector/source/CFWInfo.s
Normal file
9
injector/source/CFWInfo.s
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global svcGetCFWInfo
|
||||||
|
.type svcGetCFWInfo, %function
|
||||||
|
svcGetCFWInfo:
|
||||||
|
svc 0x2e
|
||||||
|
bx lr
|
||||||
@@ -82,23 +82,23 @@ Result FSLDR_SetPriority(u32 priority)
|
|||||||
return cmdbuf[1];
|
return cmdbuf[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FSLDR_OpenFileDirectly(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes)
|
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes)
|
||||||
{
|
{
|
||||||
u32 *cmdbuf = getThreadCommandBuffer();
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
cmdbuf[0] = IPC_MakeHeader(0x803,8,4); // 0x8030204
|
cmdbuf[0] = IPC_MakeHeader(0x803,8,4); // 0x8030204
|
||||||
cmdbuf[1] = 0;
|
cmdbuf[1] = 0;
|
||||||
cmdbuf[2] = archive.id;
|
cmdbuf[2] = archiveId;
|
||||||
cmdbuf[3] = archive.lowPath.type;
|
cmdbuf[3] = archivePath.type;
|
||||||
cmdbuf[4] = archive.lowPath.size;
|
cmdbuf[4] = archivePath.size;
|
||||||
cmdbuf[5] = path.type;
|
cmdbuf[5] = filePath.type;
|
||||||
cmdbuf[6] = path.size;
|
cmdbuf[6] = filePath.size;
|
||||||
cmdbuf[7] = openFlags;
|
cmdbuf[7] = openFlags;
|
||||||
cmdbuf[8] = attributes;
|
cmdbuf[8] = attributes;
|
||||||
cmdbuf[9] = IPC_Desc_StaticBuffer(archive.lowPath.size, 2);
|
cmdbuf[9] = IPC_Desc_StaticBuffer(archivePath.size, 2);
|
||||||
cmdbuf[10] = (u32) archive.lowPath.data;
|
cmdbuf[10] = (u32)archivePath.data;
|
||||||
cmdbuf[11] = IPC_Desc_StaticBuffer(path.size, 0);
|
cmdbuf[11] = IPC_Desc_StaticBuffer(filePath.size, 0);
|
||||||
cmdbuf[12] = (u32) path.data;
|
cmdbuf[12] = (u32)filePath.data;
|
||||||
|
|
||||||
Result ret = 0;
|
Result ret = 0;
|
||||||
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
|
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ Result fsldrInit(void);
|
|||||||
void fsldrExit(void);
|
void fsldrExit(void);
|
||||||
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version);
|
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version);
|
||||||
Result FSLDR_SetPriority(u32 priority);
|
Result FSLDR_SetPriority(u32 priority);
|
||||||
Result FSLDR_OpenFileDirectly(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes);
|
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes);
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
#include "fsldr.h"
|
#include "fsldr.h"
|
||||||
|
|
||||||
Result IFile_Open(IFile *file, FS_Archive archive, FS_Path path, u32 flags)
|
Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags)
|
||||||
{
|
{
|
||||||
Result res;
|
Result res;
|
||||||
|
|
||||||
res = FSLDR_OpenFileDirectly(&file->handle, archive, path, flags, 0);
|
res = FSLDR_OpenFileDirectly(&file->handle, archiveId, archivePath, filePath, flags, 0);
|
||||||
file->pos = 0;
|
file->pos = 0;
|
||||||
file->size = 0;
|
file->size = 0;
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ typedef struct
|
|||||||
u64 size;
|
u64 size;
|
||||||
} IFile;
|
} IFile;
|
||||||
|
|
||||||
Result IFile_Open(IFile *file, FS_Archive archive, FS_Path path, u32 flags);
|
Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags);
|
||||||
Result IFile_Close(IFile *file);
|
Result IFile_Close(IFile *file);
|
||||||
Result IFile_GetSize(IFile *file, u64 *size);
|
Result IFile_GetSize(IFile *file, u64 *size);
|
||||||
Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);
|
Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);
|
||||||
@@ -109,21 +109,20 @@ static Result allocate_shared_mem(prog_addrs_t *shared, prog_addrs_t *vaddr, int
|
|||||||
static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int is_compressed)
|
static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int is_compressed)
|
||||||
{
|
{
|
||||||
IFile file;
|
IFile file;
|
||||||
FS_Archive archive;
|
FS_Path archivePath;
|
||||||
FS_Path path;
|
FS_Path filePath;
|
||||||
Result res;
|
Result res;
|
||||||
u64 size;
|
u64 size;
|
||||||
u64 total;
|
u64 total;
|
||||||
|
|
||||||
archive.id = ARCHIVE_SAVEDATA_AND_CONTENT2;
|
archivePath.type = PATH_BINARY;
|
||||||
archive.lowPath.type = PATH_BINARY;
|
archivePath.data = &prog_handle;
|
||||||
archive.lowPath.data = &prog_handle;
|
archivePath.size = 8;
|
||||||
archive.lowPath.size = 8;
|
|
||||||
//archive.handle = prog_handle; // not needed
|
filePath.type = PATH_BINARY;
|
||||||
path.type = PATH_BINARY;
|
filePath.data = CODE_PATH;
|
||||||
path.data = CODE_PATH;
|
filePath.size = sizeof(CODE_PATH);
|
||||||
path.size = sizeof(CODE_PATH);
|
if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
|
||||||
if (R_FAILED(IFile_Open(&file, archive, path, FS_OPEN_READ)))
|
|
||||||
{
|
{
|
||||||
svcBreak(USERBREAK_ASSERT);
|
svcBreak(USERBREAK_ASSERT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,43 @@ void memcpy(void *dest, const void *src, u32 size)
|
|||||||
|
|
||||||
for(u32 i = 0; i < size; i++)
|
for(u32 i = 0; i < size; i++)
|
||||||
destc[i] = srcc[i];
|
destc[i] = srcc[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
|
{
|
||||||
|
const u8 *buf1c = (const u8 *)buf1;
|
||||||
|
const u8 *buf2c = (const u8 *)buf2;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
int cmp = buf1c[i] - buf2c[i];
|
||||||
|
if(cmp) return cmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Boyer-Moore Horspool algorithm, adapted from http://www-igm.univ-mlv.fr/~lecroq/string/node18.html#SECTION00180
|
||||||
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||||
|
{
|
||||||
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
u32 table[256];
|
||||||
|
|
||||||
|
//Preprocessing
|
||||||
|
for(u32 i = 0; i < 256; i++)
|
||||||
|
table[i] = patternSize;
|
||||||
|
for(u32 i = 0; i < patternSize - 1; i++)
|
||||||
|
table[patternc[i]] = patternSize - i - 1;
|
||||||
|
|
||||||
|
//Searching
|
||||||
|
u32 j = 0;
|
||||||
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
|
u8 c = startPos[j + patternSize - 1];
|
||||||
|
if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0)
|
||||||
|
return startPos + j;
|
||||||
|
j += table[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,6 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, u32 size);
|
void memcpy(void *dest, const void *src, u32 size);
|
||||||
|
int memcmp(const void *buf1, const void *buf2, u32 size);
|
||||||
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
||||||
@@ -1,60 +1,15 @@
|
|||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
#include "memory.h"
|
|
||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "strings.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
|
#include "CFWInfo.h"
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
static CFWInfo info;
|
||||||
#define PATH_MAX 255
|
|
||||||
#define CONFIG(a) ((loadConfig() >> (a + 16)) & 1)
|
|
||||||
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
|
|
||||||
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int memcmp(const void *buf1, const void *buf2, u32 size)
|
static void patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
|
||||||
{
|
{
|
||||||
const u8 *buf1c = (const u8 *)buf1;
|
for(u32 i = 0; i < count; i++)
|
||||||
const u8 *buf2c = (const u8 *)buf2;
|
|
||||||
|
|
||||||
for(u32 i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
int cmp = buf1c[i] - buf2c[i];
|
|
||||||
if(cmp) return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
|
||||||
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
|
||||||
{
|
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
|
||||||
|
|
||||||
//Preprocessing
|
|
||||||
u32 table[256];
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 256; ++i)
|
|
||||||
table[i] = patternSize + 1;
|
|
||||||
for(u32 i = 0; i < patternSize; ++i)
|
|
||||||
table[patternc[i]] = patternSize - i;
|
|
||||||
|
|
||||||
//Searching
|
|
||||||
u32 j = 0;
|
|
||||||
|
|
||||||
while(j <= size - patternSize)
|
|
||||||
{
|
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
|
||||||
return startPos + j;
|
|
||||||
j += table[startPos[j + patternSize]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
|
|
||||||
{
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
for(i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
u8 *found = memsearch(start, pattern, size, patSize);
|
u8 *found = memsearch(start, pattern, size, patSize);
|
||||||
|
|
||||||
@@ -69,123 +24,150 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, in
|
|||||||
size -= at + patSize;
|
size -= at + patSize;
|
||||||
start = found + patSize;
|
start = found + patSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t strnlen(const char *string, size_t maxlen)
|
static int fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
|
||||||
{
|
{
|
||||||
size_t size;
|
FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path},
|
||||||
|
archivePath = {PATH_EMPTY, 1, (u8 *)""};
|
||||||
|
|
||||||
for(size = 0; *string && size < maxlen; string++, size++);
|
return IFile_Open(file, archiveId, archivePath, filePath, flags);
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags)
|
static void loadCFWInfo(void)
|
||||||
{
|
{
|
||||||
FS_Archive archive;
|
static bool infoLoaded = false;
|
||||||
FS_Path ppath;
|
|
||||||
|
|
||||||
size_t len = strnlen(path, PATH_MAX);
|
if(!infoLoaded)
|
||||||
archive.id = id;
|
{
|
||||||
archive.lowPath.type = PATH_EMPTY;
|
svcGetCFWInfo(&info);
|
||||||
archive.lowPath.size = 1;
|
|
||||||
archive.lowPath.data = (u8 *)"";
|
|
||||||
ppath.type = PATH_ASCII;
|
|
||||||
ppath.data = path;
|
|
||||||
ppath.size = len + 1;
|
|
||||||
|
|
||||||
return IFile_Open(file, archive, ppath, flags);
|
IFile file;
|
||||||
|
if(BOOTCFG_SAFEMODE != 0 && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
|
||||||
|
IFile_Close(&file);
|
||||||
|
|
||||||
|
infoLoaded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 secureInfoExists(void)
|
static bool secureInfoExists(void)
|
||||||
{
|
{
|
||||||
static u32 secureInfoExists = 0;
|
static bool exists = false;
|
||||||
|
|
||||||
if(!secureInfoExists)
|
if(!exists)
|
||||||
{
|
{
|
||||||
IFile file;
|
IFile file;
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
|
||||||
{
|
{
|
||||||
secureInfoExists = 1;
|
exists = true;
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return secureInfoExists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 loadConfig(void)
|
static void loadCustomVerString(u16 *out, u32 *verStringSize)
|
||||||
{
|
{
|
||||||
static u32 config = 0;
|
static const char path[] = "/luma/customversion.txt";
|
||||||
|
|
||||||
if(!config)
|
IFile file;
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ)))
|
||||||
{
|
{
|
||||||
IFile file;
|
u64 fileSize;
|
||||||
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ)))
|
|
||||||
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= 19)
|
||||||
|
{
|
||||||
|
u8 buf[19];
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, fileSize)))
|
||||||
|
{
|
||||||
|
*verStringSize = (u32)fileSize;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < *verStringSize; i++)
|
||||||
|
((u8 *)out)[2 * i] = buf[i];
|
||||||
|
|
||||||
|
*verStringSize *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IFile_Close(&file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
||||||
|
{
|
||||||
|
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
|
||||||
|
If it exists it should be a decompressed binary code file */
|
||||||
|
|
||||||
|
char path[] = "/luma/code_sections/0000000000000000.bin";
|
||||||
|
progIdToStr(path + 35, progId);
|
||||||
|
|
||||||
|
IFile file;
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ)))
|
||||||
|
{
|
||||||
|
u64 fileSize;
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= size)
|
||||||
{
|
{
|
||||||
u64 total;
|
u64 total;
|
||||||
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4;
|
IFile_Read(&file, &total, code, fileSize);
|
||||||
IFile_Close(&file);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
IFile_Close(&file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||||
{
|
{
|
||||||
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
|
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
|
||||||
If it exists it should contain, for example, "EUR IT" */
|
If it exists it should contain, for example, "EUR IT" */
|
||||||
|
|
||||||
char path[] = "/luma/locales/0000000000000000.txt";
|
char path[] = "/luma/locales/0000000000000000.txt";
|
||||||
|
progIdToStr(path + 29, progId);
|
||||||
u32 i = 29;
|
|
||||||
|
|
||||||
while(progId > 0)
|
|
||||||
{
|
|
||||||
static const char hexDigits[] = "0123456789ABCDEF";
|
|
||||||
path[i--] = hexDigits[(u32)(progId & 0xF)];
|
|
||||||
progId >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFile file;
|
IFile file;
|
||||||
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
|
||||||
if(R_SUCCEEDED(ret))
|
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ)))
|
||||||
{
|
{
|
||||||
char buf[6];
|
u64 fileSize;
|
||||||
u64 total;
|
|
||||||
|
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize == 6)
|
||||||
|
{
|
||||||
|
char buf[6];
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, 6)))
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
||||||
|
|
||||||
|
if(memcmp(buf, regions[i], 3) == 0)
|
||||||
|
{
|
||||||
|
*regionId = (u8)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
||||||
|
|
||||||
|
if(memcmp(buf + 4, languages[i], 2) == 0)
|
||||||
|
{
|
||||||
|
*languageId = (u8)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = IFile_Read(&file, &total, buf, 6);
|
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
|
|
||||||
if(!R_SUCCEEDED(ret) || total < 6) return -1;
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 7; ++i)
|
|
||||||
{
|
|
||||||
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
|
||||||
|
|
||||||
if(memcmp(buf, regions[i], 3) == 0)
|
|
||||||
{
|
|
||||||
*regionId = (u8)i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 12; ++i)
|
|
||||||
{
|
|
||||||
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
|
||||||
|
|
||||||
if(memcmp(buf + 4, languages[i], 2) == 0)
|
|
||||||
{
|
|
||||||
*languageId = (u8)i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
||||||
@@ -245,8 +227,8 @@ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetC
|
|||||||
if(instr[3] == 0xEB) //We're looking for BL
|
if(instr[3] == 0xEB) //We're looking for BL
|
||||||
{
|
{
|
||||||
u8 *calledFunction = instr;
|
u8 *calledFunction = instr;
|
||||||
u32 i = 0,
|
u32 i = 0;
|
||||||
found;
|
bool found;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -301,6 +283,8 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
|
|||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size)
|
void patchCode(u64 progId, u8 *code, u32 size)
|
||||||
{
|
{
|
||||||
|
loadCFWInfo();
|
||||||
|
|
||||||
switch(progId)
|
switch(progId)
|
||||||
{
|
{
|
||||||
case 0x0004003000008F02LL: // USA Menu
|
case 0x0004003000008F02LL: // USA Menu
|
||||||
@@ -311,7 +295,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
case 0x000400300000B102LL: // TWN Menu
|
case 0x000400300000B102LL: // TWN Menu
|
||||||
{
|
{
|
||||||
static const u8 regionFreePattern[] = {
|
static const u8 regionFreePattern[] = {
|
||||||
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
|
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0
|
||||||
};
|
};
|
||||||
static const u8 regionFreePatch[] = {
|
static const u8 regionFreePatch[] = {
|
||||||
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
||||||
@@ -336,12 +320,6 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
static const u8 blockAutoUpdatesPatch[] = {
|
static const u8 blockAutoUpdatesPatch[] = {
|
||||||
0xE3, 0xA0
|
0xE3, 0xA0
|
||||||
};
|
};
|
||||||
static const u8 skipEshopUpdateCheckPattern[] = {
|
|
||||||
0x30, 0xB5, 0xF1, 0xB0
|
|
||||||
};
|
|
||||||
static const u8 skipEshopUpdateCheckPatch[] = {
|
|
||||||
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
|
|
||||||
};
|
|
||||||
|
|
||||||
//Block silent auto-updates
|
//Block silent auto-updates
|
||||||
patchMemory(code, size,
|
patchMemory(code, size,
|
||||||
@@ -351,13 +329,24 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
sizeof(blockAutoUpdatesPatch), 1
|
sizeof(blockAutoUpdatesPatch), 1
|
||||||
);
|
);
|
||||||
|
|
||||||
//Skip update checks to access the EShop
|
//Apply only if the user booted with R
|
||||||
patchMemory(code, size,
|
if((BOOTCFG_NAND != 0) != (BOOTCFG_FIRM != 0))
|
||||||
skipEshopUpdateCheckPattern,
|
{
|
||||||
sizeof(skipEshopUpdateCheckPattern), 0,
|
static const u8 skipEshopUpdateCheckPattern[] = {
|
||||||
skipEshopUpdateCheckPatch,
|
0x30, 0xB5, 0xF1, 0xB0
|
||||||
sizeof(skipEshopUpdateCheckPatch), 1
|
};
|
||||||
);
|
static const u8 skipEshopUpdateCheckPatch[] = {
|
||||||
|
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
|
||||||
|
};
|
||||||
|
|
||||||
|
//Skip update checks to access the EShop
|
||||||
|
patchMemory(code, size,
|
||||||
|
skipEshopUpdateCheckPattern,
|
||||||
|
sizeof(skipEshopUpdateCheckPattern), 0,
|
||||||
|
skipEshopUpdateCheckPatch,
|
||||||
|
sizeof(skipEshopUpdateCheckPatch), 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -365,18 +354,15 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
case 0x0004013000003202LL: // FRIENDS
|
case 0x0004013000003202LL: // FRIENDS
|
||||||
{
|
{
|
||||||
static const u8 fpdVerPattern[] = {
|
static const u8 fpdVerPattern[] = {
|
||||||
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
|
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u8 fpdVerPatch = 0x05;
|
u8 mostRecentFpdVer = 7;
|
||||||
|
|
||||||
|
u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
|
||||||
|
|
||||||
//Allow online access to work with old friends modules
|
//Allow online access to work with old friends modules
|
||||||
patchMemory(code, size,
|
if(fpdVer != NULL && fpdVer[9] < mostRecentFpdVer) fpdVer[9] = mostRecentFpdVer;
|
||||||
fpdVerPattern,
|
|
||||||
sizeof(fpdVerPattern), 9,
|
|
||||||
&fpdVerPatch,
|
|
||||||
sizeof(fpdVerPatch), 1
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -388,19 +374,69 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
case 0x0004001000027000LL: // KOR MSET
|
case 0x0004001000027000LL: // KOR MSET
|
||||||
case 0x0004001000028000LL: // TWN MSET
|
case 0x0004001000028000LL: // TWN MSET
|
||||||
{
|
{
|
||||||
if(CONFIG(6))
|
if(CONFIG(PATCHVERSTRING))
|
||||||
{
|
{
|
||||||
static const u16 verPattern[] = u"Ver.";
|
static const u16 verPattern[] = u"Ver.";
|
||||||
const u32 currentNand = BOOTCONFIG(0, 3);
|
static u16 *verString;
|
||||||
const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
|
u32 verStringSize;
|
||||||
|
|
||||||
|
u16 customVerString[19] = {0};
|
||||||
|
loadCustomVerString(customVerString, &verStringSize);
|
||||||
|
|
||||||
|
if(customVerString[0] != 0) verString = customVerString;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verStringSize = 8;
|
||||||
|
u32 currentNand = BOOTCFG_NAND,
|
||||||
|
currentFirm = BOOTCFG_FIRM;
|
||||||
|
bool matchingFirm = (currentFirm != 0) == (currentNand != 0);
|
||||||
|
|
||||||
|
static u16 verStringEmu[] = u"Emu ",
|
||||||
|
verStringEmuSys[] = u"Em S",
|
||||||
|
verStringSysEmu[] = u"SyE ";
|
||||||
|
|
||||||
|
switch(currentNand)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
verString = matchingFirm ? u" Emu" : u"EmuS";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
if(matchingFirm)
|
||||||
|
{
|
||||||
|
verStringEmu[3] = '0' + currentNand;
|
||||||
|
verString = verStringEmu;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verStringEmuSys[2] = '0' + currentNand;
|
||||||
|
verString = verStringEmuSys;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if(matchingFirm) verString = u" Sys";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(currentFirm == 1) verString = u"SysE";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verStringSysEmu[3] = '0' + currentFirm;
|
||||||
|
verString = verStringSysEmu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Patch Ver. string
|
//Patch Ver. string
|
||||||
patchMemory(code, size,
|
patchMemory(code, size,
|
||||||
verPattern,
|
verPattern,
|
||||||
sizeof(verPattern) - sizeof(u16), 0,
|
sizeof(verPattern) - 2, 0,
|
||||||
!currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
|
verString,
|
||||||
((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
|
verStringSize, 1
|
||||||
sizeof(verPattern) - sizeof(u16), 1
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,12 +460,12 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
sizeof(stopCartUpdatesPatch), 2
|
sizeof(stopCartUpdatesPatch), 2
|
||||||
);
|
);
|
||||||
|
|
||||||
u32 cpuSetting = MULTICONFIG(1);
|
u32 cpuSetting = MULTICONFIG(NEWCPU);
|
||||||
|
|
||||||
if(cpuSetting)
|
if(cpuSetting != 0)
|
||||||
{
|
{
|
||||||
static const u8 cfgN3dsCpuPattern[] = {
|
static const u8 cfgN3dsCpuPattern[] = {
|
||||||
0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00
|
0x00, 0x40, 0xA0, 0xE1, 0x07
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
||||||
@@ -448,7 +484,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
case 0x0004013000001702LL: // CFG
|
case 0x0004013000001702LL: // CFG
|
||||||
{
|
{
|
||||||
static const u8 secureinfoSigCheckPattern[] = {
|
static const u8 secureinfoSigCheckPattern[] = {
|
||||||
0x06, 0x46, 0x10, 0x48, 0xFC
|
0x06, 0x46, 0x10, 0x48
|
||||||
};
|
};
|
||||||
static const u8 secureinfoSigCheckPatch[] = {
|
static const u8 secureinfoSigCheckPatch[] = {
|
||||||
0x00, 0x26
|
0x00, 0x26
|
||||||
@@ -470,31 +506,110 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
//Use SecureInfo_C
|
//Use SecureInfo_C
|
||||||
patchMemory(code, size,
|
patchMemory(code, size,
|
||||||
secureinfoFilenamePattern,
|
secureinfoFilenamePattern,
|
||||||
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
sizeof(secureinfoFilenamePattern) - 2,
|
||||||
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
sizeof(secureinfoFilenamePattern) - 2,
|
||||||
secureinfoFilenamePatch,
|
secureinfoFilenamePatch,
|
||||||
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
|
sizeof(secureinfoFilenamePatch) - 2, 2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x0004013000003702LL: // RO
|
||||||
|
{
|
||||||
|
static const u8 sigCheckPattern[] = {
|
||||||
|
0x30, 0x40, 0x2D, 0xE9, 0x02
|
||||||
|
};
|
||||||
|
static const u8 sha256ChecksPattern1[] = {
|
||||||
|
0x30, 0x40, 0x2D, 0xE9, 0x24
|
||||||
|
};
|
||||||
|
static const u8 sha256ChecksPattern2[] = {
|
||||||
|
0xF8, 0x4F, 0x2D, 0xE9, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 stub[] = {
|
||||||
|
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 // mov r0, #0; bx lr
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable CRR0 signature (RSA2048 with SHA256) check
|
||||||
|
patchMemory(code, size,
|
||||||
|
sigCheckPattern,
|
||||||
|
sizeof(sigCheckPattern), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern1,
|
||||||
|
sizeof(sha256ChecksPattern1), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern2,
|
||||||
|
sizeof(sha256ChecksPattern2), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
case 0x0004003000008A02LL: // ErrDisp
|
||||||
|
{
|
||||||
|
if(MULTICONFIG(DEVOPTIONS) == 0)
|
||||||
|
{
|
||||||
|
static const u8 unitinfoCheckPattern1[] = {
|
||||||
|
0x14, 0x00, 0xD0, 0xE5, 0xDB
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 unitinfoCheckPattern2[] = {
|
||||||
|
0x14, 0x00, 0xD0, 0xE5, 0x01
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static const u8 unitinfoCheckPatch[] = {
|
||||||
|
0x00, 0x00, 0xA0, 0xE3
|
||||||
|
} ;
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
unitinfoCheckPattern1,
|
||||||
|
sizeof(unitinfoCheckPattern1), 0,
|
||||||
|
unitinfoCheckPatch,
|
||||||
|
sizeof(unitinfoCheckPatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
unitinfoCheckPattern2,
|
||||||
|
sizeof(unitinfoCheckPattern2), 0,
|
||||||
|
unitinfoCheckPatch,
|
||||||
|
sizeof(unitinfoCheckPatch), 3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(CONFIG(4))
|
if(CONFIG(USELANGEMUANDCODE))
|
||||||
{
|
{
|
||||||
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
|
if((u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
||||||
|
|
||||||
if(tidHigh == 0x0004000)
|
|
||||||
{
|
{
|
||||||
|
//External .code section loading
|
||||||
|
loadTitleCodeSection(progId, code, size);
|
||||||
|
|
||||||
//Language emulation
|
//Language emulation
|
||||||
u8 regionId = 0xFF,
|
u8 regionId = 0xFF,
|
||||||
languageId = 0xFF;
|
languageId = 0xFF;
|
||||||
|
loadTitleLocaleConfig(progId, ®ionId, &languageId);
|
||||||
|
|
||||||
if(R_SUCCEEDED(loadTitleLocaleConfig(progId, ®ionId, &languageId)))
|
if(regionId != 0xFF || regionId != 0xFF)
|
||||||
{
|
{
|
||||||
u32 CFGUHandleOffset;
|
u32 CFGUHandleOffset;
|
||||||
|
|
||||||
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
||||||
|
|
||||||
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
|
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
|
||||||
@@ -504,8 +619,8 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,38 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
#define CONFIG(a) (((info.config >> (a + 21)) & 1) != 0)
|
||||||
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 9)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
|
|
||||||
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
|
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
||||||
|
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
||||||
|
#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
|
||||||
|
|
||||||
|
enum multiOptions
|
||||||
|
{
|
||||||
|
DEFAULTEMU = 0,
|
||||||
|
BRIGHTNESS,
|
||||||
|
PIN,
|
||||||
|
NEWCPU
|
||||||
|
#ifdef DEV
|
||||||
|
, DEVOPTIONS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum singleOptions
|
||||||
|
{
|
||||||
|
AUTOBOOTSYS = 0,
|
||||||
|
USESYSFIRM,
|
||||||
|
USELANGEMUANDCODE,
|
||||||
|
PATCHVERSTRING,
|
||||||
|
SHOWGBABOOT,
|
||||||
|
PAYLOADSPLASH
|
||||||
|
#ifdef DEV
|
||||||
|
, PATCHACCESS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
void patchCode(u64 progId, u8 *code, u32 size);
|
void patchCode(u64 progId, u8 *code, u32 size);
|
||||||
20
injector/source/strings.c
Normal file
20
injector/source/strings.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "strings.h"
|
||||||
|
|
||||||
|
size_t strnlen(const char *string, size_t maxlen)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
for(size = 0; *string && size < maxlen; string++, size++);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void progIdToStr(char *strEnd, u64 progId)
|
||||||
|
{
|
||||||
|
while(progId)
|
||||||
|
{
|
||||||
|
static const char hexDigits[] = "0123456789ABCDEF";
|
||||||
|
*strEnd-- = hexDigits[(u32)(progId & 0xF)];
|
||||||
|
progId >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
injector/source/strings.h
Normal file
6
injector/source/strings.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
size_t strnlen(const char *string, size_t maxlen);
|
||||||
|
void progIdToStr(char *strEnd, u64 progId);
|
||||||
@@ -18,25 +18,27 @@ dir_build := build
|
|||||||
|
|
||||||
ASFLAGS := -mcpu=arm946e-s
|
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 -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||||
LDFLAGS := -nostartfiles
|
LDFLAGS := -nostdlib
|
||||||
|
|
||||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).bin
|
all: ../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).bin: $(dir_build)/$(name).elf
|
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
|
$(dir_build)/memory.o: CFLAGS += -O3
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
@@ -44,12 +46,4 @@ $(dir_build)/%.o: $(dir_source)/%.c
|
|||||||
$(dir_build)/%.o: $(dir_source)/%.s
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
|
||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
|
||||||
include $(call rwildcard, $(dir_build), *.d)
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x24F00000;
|
. = 0x24FFFF00;
|
||||||
.text.start : { *(.text.start) }
|
.text.start : { *(.text.start) }
|
||||||
.text : { *(.text) }
|
.text : { *(.text) }
|
||||||
.data : { *(.data) }
|
.data : { *(.data) }
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
|
||||||
#define BUTTON_RIGHT (1 << 4)
|
|
||||||
#define BUTTON_LEFT (1 << 5)
|
|
||||||
#define BUTTON_UP (1 << 6)
|
|
||||||
#define BUTTON_DOWN (1 << 7)
|
|
||||||
#define BUTTON_X (1 << 10)
|
|
||||||
#define BUTTON_Y (1 << 11)
|
|
||||||
#define BUTTON_R1 (1 << 8)
|
|
||||||
#define BUTTON_SELECT (1 << 2)
|
|
||||||
27
loader/source/cache.h
Normal file
27
loader/source/cache.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void flushCaches(void);
|
||||||
52
loader/source/cache.s
Normal file
52
loader/source/cache.s
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.arm
|
||||||
|
.global flushCaches
|
||||||
|
.type flushCaches STT_FUNC
|
||||||
|
|
||||||
|
flushCaches:
|
||||||
|
@ Clean and flush data cache
|
||||||
|
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
|
||||||
|
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||||
|
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||||
|
@ Implemented in bootROM at address 0xffff0830
|
||||||
|
|
||||||
|
mov r1, #0 @ segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 @ line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 @ generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||||
|
add r0, #0x20 @ increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||||
|
|
||||||
|
@ Flush instruction cache
|
||||||
|
mcr p15, 0, r1, c7, c5, 0
|
||||||
|
|
||||||
|
bx lr
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
----------------------------------------------------------------------------
|
|
||||||
Revision history of FatFs module
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
R0.00 (February 26, 2006)
|
|
||||||
|
|
||||||
Prototype.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.01 (April 29, 2006)
|
|
||||||
|
|
||||||
First stable version.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.02 (June 01, 2006)
|
|
||||||
|
|
||||||
Added FAT12 support.
|
|
||||||
Removed unbuffered mode.
|
|
||||||
Fixed a problem on small (<32M) partition.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.02a (June 10, 2006)
|
|
||||||
|
|
||||||
Added a configuration option (_FS_MINIMUM).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.03 (September 22, 2006)
|
|
||||||
|
|
||||||
Added f_rename().
|
|
||||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.03a (December 11, 2006)
|
|
||||||
|
|
||||||
Improved cluster scan algorithm to write files fast.
|
|
||||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04 (February 04, 2007)
|
|
||||||
|
|
||||||
Added f_mkfs().
|
|
||||||
Supported multiple drive system.
|
|
||||||
Changed some interfaces for multiple drive system.
|
|
||||||
Changed f_mountdrv() to f_mount().
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04a (April 01, 2007)
|
|
||||||
|
|
||||||
Supported multiple partitions on a physical drive.
|
|
||||||
Added a capability of extending file size to f_lseek().
|
|
||||||
Added minimization level 3.
|
|
||||||
Fixed an endian sensitive code in f_mkfs().
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04b (May 05, 2007)
|
|
||||||
|
|
||||||
Added a configuration option _USE_NTFLAG.
|
|
||||||
Added FSINFO support.
|
|
||||||
Fixed DBCS name can result FR_INVALID_NAME.
|
|
||||||
Fixed short seek (<= csize) collapses the file object.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.05 (August 25, 2007)
|
|
||||||
|
|
||||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
|
||||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
|
||||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.05a (February 03, 2008)
|
|
||||||
|
|
||||||
Added f_truncate() and f_utime().
|
|
||||||
Fixed off by one error at FAT sub-type determination.
|
|
||||||
Fixed btr in f_read() can be mistruncated.
|
|
||||||
Fixed cached sector is not flushed when create and close without write.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.06 (April 01, 2008)
|
|
||||||
|
|
||||||
Added fputc(), fputs(), fprintf() and fgets().
|
|
||||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07 (April 01, 2009)
|
|
||||||
|
|
||||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
|
||||||
Added long file name feature. (_USE_LFN)
|
|
||||||
Added multiple code page feature. (_CODE_PAGE)
|
|
||||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
|
||||||
Added auto cluster size selection to f_mkfs().
|
|
||||||
Added rewind option to f_readdir().
|
|
||||||
Changed result code of critical errors.
|
|
||||||
Renamed string functions to avoid name collision.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07a (April 14, 2009)
|
|
||||||
|
|
||||||
Septemberarated out OS dependent code on reentrant cfg.
|
|
||||||
Added multiple sector size feature.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07c (June 21, 2009)
|
|
||||||
|
|
||||||
Fixed f_unlink() can return FR_OK on error.
|
|
||||||
Fixed wrong cache control in f_lseek().
|
|
||||||
Added relative path feature.
|
|
||||||
Added f_chdir() and f_chdrive().
|
|
||||||
Added proper case conversion to extended character.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07e (November 03, 2009)
|
|
||||||
|
|
||||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
|
||||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
|
||||||
Fixed name matching error on the 13 character boundary.
|
|
||||||
Added a configuration option, _LFN_UNICODE.
|
|
||||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08 (May 15, 2010)
|
|
||||||
|
|
||||||
Added a memory configuration option. (_USE_LFN = 3)
|
|
||||||
Added file lock feature. (_FS_SHARE)
|
|
||||||
Added fast seek feature. (_USE_FASTSEEK)
|
|
||||||
Changed some types on the API, XCHAR->TCHAR.
|
|
||||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
|
||||||
String functions support UTF-8 encoding files on Unicode cfg.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08a (August 16, 2010)
|
|
||||||
|
|
||||||
Added f_getcwd(). (_FS_RPATH = 2)
|
|
||||||
Added sector erase feature. (_USE_ERASE)
|
|
||||||
Moved file lock semaphore table from fs object to the bss.
|
|
||||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08b (January 15, 2011)
|
|
||||||
|
|
||||||
Fast seek feature is also applied to f_read() and f_write().
|
|
||||||
f_lseek() reports required table size on creating CLMP.
|
|
||||||
Extended format syntax of f_printf().
|
|
||||||
Ignores duplicated directory separators in given path name.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09 (September 06, 2011)
|
|
||||||
|
|
||||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
|
||||||
Added f_fdisk().
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09a (August 27, 2012)
|
|
||||||
|
|
||||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
|
||||||
Changed option name _FS_SHARE to _FS_LOCK.
|
|
||||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09b (January 24, 2013)
|
|
||||||
|
|
||||||
Added f_setlabel() and f_getlabel().
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10 (October 02, 2013)
|
|
||||||
|
|
||||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
|
||||||
Added f_closedir().
|
|
||||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
|
||||||
Added forced mount feature with changes of f_mount().
|
|
||||||
Improved behavior of volume auto detection.
|
|
||||||
Improved write throughput of f_puts() and f_printf().
|
|
||||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
|
||||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
|
||||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10a (January 15, 2014)
|
|
||||||
|
|
||||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
|
||||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
|
||||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
|
||||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
|
||||||
Fixed f_close() invalidates the file object without volume lock.
|
|
||||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
|
||||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10c (November 09, 2014)
|
|
||||||
|
|
||||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
|
||||||
Changed option name _USE_ERASE to _USE_TRIM.
|
|
||||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
|
||||||
Fixed a potential problem of FAT access that can appear on disk error.
|
|
||||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.11 (February 09, 2015)
|
|
||||||
|
|
||||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
|
||||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
|
||||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.11a (September 05, 2015)
|
|
||||||
|
|
||||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
|
||||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
|
||||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
|
||||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
|
||||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.12 (April 12, 2016)
|
|
||||||
|
|
||||||
Added support of exFAT file system. (_FS_EXFAT)
|
|
||||||
Added f_expand(). (_USE_EXPAND)
|
|
||||||
Changed some members in FINFO structure and behavior of f_readdir().
|
|
||||||
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
|
|
||||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
|
||||||
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FatFs Module Source Files R0.12
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* If a working storage control module is available, it should be */
|
|
||||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
|
||||||
/* This is an example of glue functions to attach various exsisting */
|
|
||||||
/* storage control modules to the FatFs module with a defined API. */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "diskio.h" /* FatFs lower layer API */
|
|
||||||
#include "sdmmc/sdmmc.h"
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Get Drive Status */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DSTATUS disk_status (
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Inidialize a Drive */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DSTATUS disk_initialize (
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
sdmmc_sdcard_init();
|
|
||||||
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Read Sector(s) */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DRESULT disk_read (
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
|
||||||
BYTE *buff, /* Data buffer to store read data */
|
|
||||||
DWORD sector, /* Sector address in LBA */
|
|
||||||
UINT count /* Number of sectors to read */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if(sdmmc_sdcard_readsectors(sector, count, buff))
|
|
||||||
return RES_PARERR;
|
|
||||||
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Write Sector(s) */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#if _USE_WRITE
|
|
||||||
DRESULT disk_write (
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
|
||||||
__attribute__((unused))
|
|
||||||
const BYTE *buff, /* Data to be written */
|
|
||||||
__attribute__((unused))
|
|
||||||
DWORD sector, /* Sector address in LBA */
|
|
||||||
__attribute__((unused))
|
|
||||||
UINT count /* Number of sectors to write */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return RES_OK;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Miscellaneous Functions */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#if _USE_IOCTL
|
|
||||||
DRESULT disk_ioctl (
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
|
||||||
__attribute__((unused))
|
|
||||||
BYTE cmd, /* Control code */
|
|
||||||
__attribute__((unused))
|
|
||||||
void *buff /* Buffer to send/receive control data */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return RES_PARERR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/*-----------------------------------------------------------------------/
|
|
||||||
/ Low level disk interface modlue include file (C)ChaN, 2014 /
|
|
||||||
/-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef _DISKIO_DEFINED
|
|
||||||
#define _DISKIO_DEFINED
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define _USE_WRITE 1 /* 1: Enable disk_write function */
|
|
||||||
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
|
|
||||||
|
|
||||||
#include "integer.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Status of Disk Functions */
|
|
||||||
typedef BYTE DSTATUS;
|
|
||||||
|
|
||||||
/* Results of Disk Functions */
|
|
||||||
typedef enum {
|
|
||||||
RES_OK = 0, /* 0: Successful */
|
|
||||||
RES_ERROR, /* 1: R/W Error */
|
|
||||||
RES_WRPRT, /* 2: Write Protected */
|
|
||||||
RES_NOTRDY, /* 3: Not Ready */
|
|
||||||
RES_PARERR /* 4: Invalid Parameter */
|
|
||||||
} DRESULT;
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------*/
|
|
||||||
/* Prototypes for disk control functions */
|
|
||||||
|
|
||||||
|
|
||||||
DSTATUS disk_initialize (BYTE pdrv);
|
|
||||||
DSTATUS disk_status (BYTE pdrv);
|
|
||||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
|
||||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
|
||||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
|
||||||
|
|
||||||
|
|
||||||
/* Disk Status Bits (DSTATUS) */
|
|
||||||
|
|
||||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
|
||||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
|
||||||
#define STA_PROTECT 0x04 /* Write protected */
|
|
||||||
|
|
||||||
|
|
||||||
/* Command code for disk_ioctrl fucntion */
|
|
||||||
|
|
||||||
/* Generic command (Used by FatFs) */
|
|
||||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
|
||||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
|
||||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
|
||||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
|
||||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
|
||||||
|
|
||||||
/* Generic command (Not used by FatFs) */
|
|
||||||
#define CTRL_POWER 5 /* Get/Set power status */
|
|
||||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
|
||||||
#define CTRL_EJECT 7 /* Eject media */
|
|
||||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
|
||||||
|
|
||||||
/* MMC/SDC specific ioctl command */
|
|
||||||
#define MMC_GET_TYPE 10 /* Get card type */
|
|
||||||
#define MMC_GET_CSD 11 /* Get CSD */
|
|
||||||
#define MMC_GET_CID 12 /* Get CID */
|
|
||||||
#define MMC_GET_OCR 13 /* Get OCR */
|
|
||||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
|
||||||
|
|
||||||
/* ATA/CF specific ioctl command */
|
|
||||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
|
||||||
#define ATA_GET_MODEL 21 /* Get model name */
|
|
||||||
#define ATA_GET_SN 22 /* Get serial number */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,366 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
|
|
||||||
/----------------------------------------------------------------------------/
|
|
||||||
/ FatFs module is a free software that opened under license policy of
|
|
||||||
/ following conditions.
|
|
||||||
/
|
|
||||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
|
||||||
/
|
|
||||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
/ this condition and the following disclaimer.
|
|
||||||
/
|
|
||||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
|
||||||
/ and any warranties related to this software are DISCLAIMED.
|
|
||||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
|
||||||
/ by use of this software.
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
|
||||||
#define _FATFS 88100 /* Revision ID */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "integer.h" /* Basic integer types */
|
|
||||||
#include "ffconf.h" /* FatFs configuration options */
|
|
||||||
#if _FATFS != _FFCONF
|
|
||||||
#error Wrong configuration file (ffconf.h).
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Definitions of volume management */
|
|
||||||
|
|
||||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
|
||||||
typedef struct {
|
|
||||||
BYTE pd; /* Physical drive number */
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Type of path name strings on FatFs API */
|
|
||||||
|
|
||||||
#if _LFN_UNICODE /* Unicode string */
|
|
||||||
#if _USE_LFN == 0
|
|
||||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
|
||||||
#endif
|
|
||||||
#ifndef _INC_TCHAR
|
|
||||||
typedef WCHAR TCHAR;
|
|
||||||
#define _T(x) L ## x
|
|
||||||
#define _TEXT(x) L ## x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else /* ANSI/OEM string */
|
|
||||||
#ifndef _INC_TCHAR
|
|
||||||
typedef char TCHAR;
|
|
||||||
#define _T(x) x
|
|
||||||
#define _TEXT(x) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* File system object structure (FATFS) */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BYTE fs_type; /* File system type (0:N/A) */
|
|
||||||
BYTE drv; /* Physical drive number */
|
|
||||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
|
||||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
|
||||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
|
||||||
WORD id; /* File system mount ID */
|
|
||||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
|
||||||
WORD csize; /* Cluster size [sectors] */
|
|
||||||
#if _MAX_SS != _MIN_SS
|
|
||||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
|
||||||
#endif
|
|
||||||
#if _FS_EXFAT
|
|
||||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
|
||||||
#endif
|
|
||||||
#if _FS_REENTRANT
|
|
||||||
_SYNC_t sobj; /* Identifier of sync object */
|
|
||||||
#endif
|
|
||||||
#if !_FS_READONLY
|
|
||||||
DWORD last_clst; /* Last allocated cluster */
|
|
||||||
DWORD free_clst; /* Number of free clusters */
|
|
||||||
#endif
|
|
||||||
#if _FS_RPATH != 0
|
|
||||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
|
||||||
#if _FS_EXFAT
|
|
||||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
|
||||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
|
||||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
|
||||||
DWORD fsize; /* Size of an FAT [sectors] */
|
|
||||||
DWORD volbase; /* Volume base sector */
|
|
||||||
DWORD fatbase; /* FAT base sector */
|
|
||||||
DWORD dirbase; /* Root directory base sector/cluster */
|
|
||||||
DWORD database; /* Data base sector */
|
|
||||||
DWORD winsect; /* Current sector appearing in the win[] */
|
|
||||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
|
||||||
} FATFS;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Type of file size variables and object identifier */
|
|
||||||
|
|
||||||
#if _FS_EXFAT
|
|
||||||
#if _USE_LFN == 0
|
|
||||||
#error LFN must be enabled when enable exFAT
|
|
||||||
#endif
|
|
||||||
typedef QWORD FSIZE_t;
|
|
||||||
#else
|
|
||||||
typedef DWORD FSIZE_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Object ID and allocation information (_FDID) */
|
|
||||||
|
|
||||||
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) */
|
|
||||||
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 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) */
|
|
||||||
#endif
|
|
||||||
#if _FS_LOCK != 0
|
|
||||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
|
||||||
#endif
|
|
||||||
} _FDID;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* File object structure (FIL) */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
_FDID obj; /* Object identifier */
|
|
||||||
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 (not valid when fprt is 0) */
|
|
||||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
|
||||||
#if !_FS_READONLY
|
|
||||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
|
||||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
|
||||||
#endif
|
|
||||||
#if _USE_FASTSEEK
|
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
|
||||||
#endif
|
|
||||||
#if !_FS_TINY
|
|
||||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
|
||||||
#endif
|
|
||||||
} FIL;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Directory object structure (DIR) */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
_FDID obj; /* Object identifier */
|
|
||||||
DWORD dptr; /* Current read/write offset */
|
|
||||||
DWORD clust; /* Current cluster */
|
|
||||||
DWORD sect; /* Current sector */
|
|
||||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
|
||||||
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
|
|
||||||
#if _USE_LFN != 0
|
|
||||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
|
||||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
|
||||||
#endif
|
|
||||||
#if _USE_FIND
|
|
||||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
|
||||||
#endif
|
|
||||||
} DIR;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* File information structure (FILINFO) */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FSIZE_t fsize; /* File size */
|
|
||||||
WORD fdate; /* Modified date */
|
|
||||||
WORD ftime; /* Modified time */
|
|
||||||
BYTE fattrib; /* File attribute */
|
|
||||||
#if _USE_LFN != 0
|
|
||||||
TCHAR altname[13]; /* Altenative file name */
|
|
||||||
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
|
|
||||||
#else
|
|
||||||
TCHAR fname[13]; /* File name */
|
|
||||||
#endif
|
|
||||||
} FILINFO;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* File function return code (FRESULT) */
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FR_OK = 0, /* (0) Succeeded */
|
|
||||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
|
||||||
FR_INT_ERR, /* (2) Assertion failed */
|
|
||||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
|
||||||
FR_NO_FILE, /* (4) Could not find the file */
|
|
||||||
FR_NO_PATH, /* (5) Could not find the path */
|
|
||||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
|
||||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
|
||||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
|
||||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
|
||||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
|
||||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
|
||||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
|
||||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
|
||||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
|
||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
|
||||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
|
|
||||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
|
||||||
} FRESULT;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------*/
|
|
||||||
/* FatFs module application interface */
|
|
||||||
|
|
||||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
|
||||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
|
||||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
|
||||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
|
||||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
|
|
||||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
|
||||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
|
||||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
|
||||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
|
||||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
|
||||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
|
||||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
|
||||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
|
||||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
|
||||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
|
||||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
|
||||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
|
|
||||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
|
|
||||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
|
||||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
|
||||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
|
||||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
|
||||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
|
||||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
|
||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
|
||||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
|
||||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
|
||||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
|
||||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
|
||||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
|
||||||
|
|
||||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
|
||||||
#define f_error(fp) ((fp)->err)
|
|
||||||
#define f_tell(fp) ((fp)->fptr)
|
|
||||||
#define f_size(fp) ((fp)->obj.objsize)
|
|
||||||
#define f_rewind(fp) f_lseek((fp), 0)
|
|
||||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
|
||||||
|
|
||||||
#ifndef EOF
|
|
||||||
#define EOF (-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------*/
|
|
||||||
/* Additional user defined functions */
|
|
||||||
|
|
||||||
/* RTC function */
|
|
||||||
#if !_FS_READONLY && !_FS_NORTC
|
|
||||||
DWORD get_fattime (void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Unicode support functions */
|
|
||||||
#if _USE_LFN != 0 /* Unicode - OEM code conversion */
|
|
||||||
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
|
|
||||||
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
|
|
||||||
#if _USE_LFN == 3 /* Memory functions */
|
|
||||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
|
||||||
void ff_memfree (void* mblock); /* Free memory block */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Sync functions */
|
|
||||||
#if _FS_REENTRANT
|
|
||||||
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
|
|
||||||
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
|
|
||||||
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
|
|
||||||
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------*/
|
|
||||||
/* Flags and offset address */
|
|
||||||
|
|
||||||
|
|
||||||
/* File access control and file status flags (FIL.flag) */
|
|
||||||
|
|
||||||
#define FA_READ 0x01
|
|
||||||
#define FA_WRITE 0x02
|
|
||||||
#define FA_OPEN_EXISTING 0x00
|
|
||||||
#define FA_CREATE_NEW 0x04
|
|
||||||
#define FA_CREATE_ALWAYS 0x08
|
|
||||||
#define FA_OPEN_ALWAYS 0x10
|
|
||||||
#define _FA_MODIFIED 0x20
|
|
||||||
#define _FA_DIRTY 0x40
|
|
||||||
|
|
||||||
|
|
||||||
/* FAT sub type (FATFS.fs_type) */
|
|
||||||
|
|
||||||
#define FS_FAT12 1
|
|
||||||
#define FS_FAT16 2
|
|
||||||
#define FS_FAT32 3
|
|
||||||
#define FS_EXFAT 4
|
|
||||||
|
|
||||||
|
|
||||||
/* File attribute bits for directory entry */
|
|
||||||
|
|
||||||
#define AM_RDO 0x01 /* Read only */
|
|
||||||
#define AM_HID 0x02 /* Hidden */
|
|
||||||
#define AM_SYS 0x04 /* System */
|
|
||||||
#define AM_VOL 0x08 /* Volume label */
|
|
||||||
#define AM_LFN 0x0F /* LFN entry */
|
|
||||||
#define AM_DIR 0x10 /* Directory */
|
|
||||||
#define AM_ARC 0x20 /* Archive */
|
|
||||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
|
||||||
|
|
||||||
|
|
||||||
/* Fast seek controls */
|
|
||||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _FATFS */
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define _FFCONF 88100 /* Revision ID */
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ Function Configurations
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define _FS_READONLY 1
|
|
||||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
|
||||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
|
||||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
|
||||||
/ and optional writing functions as well. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 1
|
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
|
||||||
/
|
|
||||||
/ 0: All basic functions are enabled.
|
|
||||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
|
||||||
/ are removed.
|
|
||||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
|
||||||
/ 3: f_lseek() function is removed in addition to 2. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_STRFUNC 0
|
|
||||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
|
|
||||||
/ f_printf().
|
|
||||||
/
|
|
||||||
/ 0: Disable string functions.
|
|
||||||
/ 1: Enable without LF-CRLF conversion.
|
|
||||||
/ 2: Enable with LF-CRLF conversion. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_FIND 1
|
|
||||||
/* This option switches filtered directory read functions, f_findfirst() and
|
|
||||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_MKFS 0
|
|
||||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_FASTSEEK 0
|
|
||||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_EXPAND 0
|
|
||||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_CHMOD 0
|
|
||||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
|
||||||
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_LABEL 0
|
|
||||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
|
||||||
/ (0:Disable or 1:Enable) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_FORWARD 0
|
|
||||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
|
||||||
/ To enable it, also _FS_TINY need to be 1. */
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ Locale and Namespace Configurations
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define _CODE_PAGE 1
|
|
||||||
/* 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)
|
|
||||||
/ 437 - U.S.
|
|
||||||
/ 720 - Arabic
|
|
||||||
/ 737 - Greek
|
|
||||||
/ 771 - KBL
|
|
||||||
/ 775 - Baltic
|
|
||||||
/ 850 - Latin 1
|
|
||||||
/ 852 - Latin 2
|
|
||||||
/ 855 - Cyrillic
|
|
||||||
/ 857 - Turkish
|
|
||||||
/ 860 - Portuguese
|
|
||||||
/ 861 - Icelandic
|
|
||||||
/ 862 - Hebrew
|
|
||||||
/ 863 - Canadian French
|
|
||||||
/ 864 - Arabic
|
|
||||||
/ 865 - Nordic
|
|
||||||
/ 866 - Russian
|
|
||||||
/ 869 - Greek 2
|
|
||||||
/ 932 - Japanese (DBCS)
|
|
||||||
/ 936 - Simplified Chinese (DBCS)
|
|
||||||
/ 949 - Korean (DBCS)
|
|
||||||
/ 950 - Traditional Chinese (DBCS)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_LFN 0
|
|
||||||
#define _MAX_LFN 255
|
|
||||||
/* The _USE_LFN switches the support of long file name (LFN).
|
|
||||||
/
|
|
||||||
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
|
||||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
|
||||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
|
||||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
|
||||||
/
|
|
||||||
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
|
|
||||||
/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
|
|
||||||
/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
|
|
||||||
/ It should be set 255 to support full featured LFN operations.
|
|
||||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
|
||||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
|
||||||
/ ff_memfree(), must be added to the project. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _LFN_UNICODE 0
|
|
||||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
|
||||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
|
||||||
/ This option also affects behavior of string I/O functions. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _STRF_ENCODE 3
|
|
||||||
/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to
|
|
||||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
|
||||||
/
|
|
||||||
/ 0: ANSI/OEM
|
|
||||||
/ 1: UTF-16LE
|
|
||||||
/ 2: UTF-16BE
|
|
||||||
/ 3: UTF-8
|
|
||||||
/
|
|
||||||
/ This option has no effect when _LFN_UNICODE == 0. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_RPATH 0
|
|
||||||
/* This option configures support of relative path.
|
|
||||||
/
|
|
||||||
/ 0: Disable relative path and remove related functions.
|
|
||||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
|
||||||
/ 2: f_getcwd() function is available in addition to 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ Drive/Volume Configurations
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define _VOLUMES 1
|
|
||||||
/* Number of volumes (logical drives) to be used. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _STR_VOLUME_ID 0
|
|
||||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
|
||||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
|
||||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
|
||||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
|
||||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
|
||||||
/ the drive ID strings are: A-Z and 0-9. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _MULTI_PARTITION 0
|
|
||||||
/* This option switches support of multi-partition on a physical drive.
|
|
||||||
/ By default (0), each logical drive number is bound to the same physical drive
|
|
||||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
|
||||||
/ When multi-partition is enabled (1), each logical drive number can be bound to
|
|
||||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
|
||||||
/ funciton will be available. */
|
|
||||||
|
|
||||||
|
|
||||||
#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
|
|
||||||
/ 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. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _USE_TRIM 0
|
|
||||||
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
|
|
||||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
|
||||||
/ disk_ioctl() function. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_NOFSINFO 0
|
|
||||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
|
||||||
/ option, and f_getfree() function at first time after volume mount will force
|
|
||||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
|
||||||
/
|
|
||||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
|
||||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
|
||||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
|
||||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
|
||||||
/ System Configurations
|
|
||||||
/---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define _FS_TINY 0
|
|
||||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
|
||||||
/ At the tiny configuration, size of the file object (FIL) is reduced _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. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_EXFAT 0
|
|
||||||
/* This option switches support of exFAT file system in addition to the traditional
|
|
||||||
/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
|
|
||||||
/ Note that enabling exFAT discards C89 compatibility. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_NORTC 1
|
|
||||||
#define _NORTC_MON 3
|
|
||||||
#define _NORTC_MDAY 1
|
|
||||||
#define _NORTC_YEAR 2016
|
|
||||||
/* 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.
|
|
||||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_LOCK 0
|
|
||||||
/* The option _FS_LOCK switches file lock function to control duplicated file open
|
|
||||||
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
|
||||||
/ is 1.
|
|
||||||
/
|
|
||||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
|
||||||
/ should avoid illegal open, remove and rename to the open objects.
|
|
||||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
|
||||||
/ can be opened simultaneously under file lock control. Note that the file
|
|
||||||
/ lock control is independent of re-entrancy. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_REENTRANT 0
|
|
||||||
#define _FS_TIMEOUT 1000
|
|
||||||
#define _SYNC_t HANDLE
|
|
||||||
/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
|
||||||
/ module itself. Note that regardless of this option, file access to different
|
|
||||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
|
||||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
|
||||||
/ to the same volume is under control of this function.
|
|
||||||
/
|
|
||||||
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
|
||||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
|
||||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
|
||||||
/ function, must be added to the project. Samples are available in
|
|
||||||
/ option/syscall.c.
|
|
||||||
/
|
|
||||||
/ 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
|
|
||||||
/ included somewhere in the scope of ff.c. */
|
|
||||||
|
|
||||||
|
|
||||||
/*--- End of configuration options ---*/
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*-------------------------------------------*/
|
|
||||||
/* Integer type definitions for FatFs module */
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef _FF_INTEGER
|
|
||||||
#define _FF_INTEGER
|
|
||||||
|
|
||||||
#ifdef _WIN32 /* FatFs development platform */
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
typedef unsigned __int64 QWORD;
|
|
||||||
|
|
||||||
|
|
||||||
#else /* Embedded platform */
|
|
||||||
|
|
||||||
/* These types MUST be 16-bit or 32-bit */
|
|
||||||
typedef int INT;
|
|
||||||
typedef unsigned int UINT;
|
|
||||||
|
|
||||||
/* This type MUST be 8-bit */
|
|
||||||
typedef unsigned char BYTE;
|
|
||||||
|
|
||||||
/* These types MUST be 16-bit */
|
|
||||||
typedef short SHORT;
|
|
||||||
typedef unsigned short WORD;
|
|
||||||
typedef unsigned short WCHAR;
|
|
||||||
|
|
||||||
/* These types MUST be 32-bit */
|
|
||||||
typedef long LONG;
|
|
||||||
typedef unsigned long DWORD;
|
|
||||||
|
|
||||||
/* This type MUST be 64-bit (Remove this for C89 compatibility) */
|
|
||||||
typedef unsigned long long QWORD;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "../../types.h"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
void ioDelay(u32 us);
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
.arm
|
|
||||||
.global ioDelay
|
|
||||||
.type ioDelay STT_FUNC
|
|
||||||
|
|
||||||
@ioDelay ( u32 us )
|
|
||||||
ioDelay:
|
|
||||||
ldr r1, =0x18000000 @ VRAM
|
|
||||||
1:
|
|
||||||
@ Loop doing uncached reads from VRAM to make loop timing more reliable
|
|
||||||
ldr r2, [r1]
|
|
||||||
subs r0, #1
|
|
||||||
bgt 1b
|
|
||||||
bx lr
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include "sdmmc.h"
|
|
||||||
#include "delay.h"
|
|
||||||
|
|
||||||
static struct mmcdevice handleSD;
|
|
||||||
|
|
||||||
static inline u16 sdmmc_read16(u16 reg) {
|
|
||||||
return *(vu16*)(SDMMC_BASE + reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdmmc_write16(u16 reg, u16 val) {
|
|
||||||
*(vu16*)(SDMMC_BASE + reg) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 sdmmc_read32(u16 reg) {
|
|
||||||
return *(vu32*)(SDMMC_BASE + reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdmmc_write32(u16 reg, u32 val) {
|
|
||||||
*(vu32*)(SDMMC_BASE + reg) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
|
|
||||||
u16 val = sdmmc_read16(reg);
|
|
||||||
val &= ~clear;
|
|
||||||
val |= set;
|
|
||||||
sdmmc_write16(reg, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void setckl(u32 data)
|
|
||||||
{
|
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
|
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
|
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx)
|
|
||||||
{
|
|
||||||
return (ctx->error << 29) >> 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
|
|
||||||
{
|
|
||||||
sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
|
|
||||||
setckl(ctx->clk);
|
|
||||||
if (ctx->SDOPT == 0) {
|
|
||||||
sdmmc_mask16(REG_SDOPT, 0, 0x8000);
|
|
||||||
} else {
|
|
||||||
sdmmc_mask16(REG_SDOPT, 0x8000, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
|
|
||||||
{
|
|
||||||
bool getSDRESP = (cmd << 15) >> 31;
|
|
||||||
u16 flags = (cmd << 15) >> 31;
|
|
||||||
const bool readdata = cmd & 0x20000;
|
|
||||||
const bool writedata = cmd & 0x40000;
|
|
||||||
|
|
||||||
if (readdata || writedata)
|
|
||||||
flags |= TMIO_STAT0_DATAEND;
|
|
||||||
|
|
||||||
ctx->error = 0;
|
|
||||||
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
|
|
||||||
sdmmc_write16(REG_SDIRMASK0,0);
|
|
||||||
sdmmc_write16(REG_SDIRMASK1,0);
|
|
||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
|
||||||
sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
|
|
||||||
|
|
||||||
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
|
|
||||||
sdmmc_write16(REG_SDCMDARG1,args >> 16);
|
|
||||||
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
|
|
||||||
|
|
||||||
u32 size = ctx->size;
|
|
||||||
vu8 *dataPtr = ctx->data;
|
|
||||||
|
|
||||||
bool useBuf = ( NULL != dataPtr );
|
|
||||||
|
|
||||||
u16 status0 = 0;
|
|
||||||
while(true) {
|
|
||||||
u16 status1 = sdmmc_read16(REG_SDSTATUS1);
|
|
||||||
if (status1 & TMIO_STAT1_RXRDY) {
|
|
||||||
if (readdata && useBuf) {
|
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
|
|
||||||
if (size > 0x1FF) {
|
|
||||||
for(int i = 0; i<0x200; i+=2) {
|
|
||||||
u16 data = sdmmc_read16(REG_SDFIFO);
|
|
||||||
*dataPtr++ = data & 0xFF;
|
|
||||||
*dataPtr++ = data >> 8;
|
|
||||||
}
|
|
||||||
size -= 0x200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status1 & TMIO_STAT1_TXRQ) {
|
|
||||||
if (writedata && useBuf) {
|
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
|
|
||||||
if (size > 0x1FF) {
|
|
||||||
for (int i = 0; i<0x200; i+=2) {
|
|
||||||
u16 data = *dataPtr++;
|
|
||||||
data |= *dataPtr++ << 8;
|
|
||||||
sdmmc_write16(REG_SDFIFO, data);
|
|
||||||
}
|
|
||||||
size -= 0x200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status1 & TMIO_MASK_GW) {
|
|
||||||
ctx->error |= 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
|
|
||||||
status0 = sdmmc_read16(REG_SDSTATUS0);
|
|
||||||
if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
|
||||||
ctx->error |= 0x1;
|
|
||||||
if (status0 & TMIO_STAT0_DATAEND)
|
|
||||||
ctx->error |= 0x2;
|
|
||||||
|
|
||||||
if ((status0 & flags) == flags)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
|
|
||||||
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
|
|
||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
|
||||||
|
|
||||||
if (getSDRESP != 0) {
|
|
||||||
ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16);
|
|
||||||
ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16);
|
|
||||||
ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16);
|
|
||||||
ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
|
|
||||||
{
|
|
||||||
if (handleSD.isSDHC == 0)
|
|
||||||
sector_no <<= 9;
|
|
||||||
inittarget(&handleSD);
|
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
|
||||||
|
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
|
||||||
handleSD.data = out;
|
|
||||||
handleSD.size = numsectors << 9;
|
|
||||||
sdmmc_send_command(&handleSD,0x33C12,sector_no);
|
|
||||||
return geterror(&handleSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 calcSDSize(u8* csd, int type)
|
|
||||||
{
|
|
||||||
u32 result = 0;
|
|
||||||
if (type == -1) type = csd[14] >> 6;
|
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
u32 block_len = csd[9] & 0xf;
|
|
||||||
block_len = 1u << block_len;
|
|
||||||
u32 mult = (u32)(csd[4] >> 7) | (u32)((csd[5] & 3) << 1);
|
|
||||||
mult = 1u << (mult + 2);
|
|
||||||
result = csd[8] & 3;
|
|
||||||
result = (result << 8) | csd[7];
|
|
||||||
result = (result << 2) | (csd[6] >> 6);
|
|
||||||
result = (result + 1) * mult * block_len / 512;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
result = csd[7] & 0x3f;
|
|
||||||
result = (result << 8) | csd[6];
|
|
||||||
result = (result << 8) | csd[5];
|
|
||||||
result = (result + 1) * 1024;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; //Do nothing otherwise
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitSD()
|
|
||||||
{
|
|
||||||
//SD
|
|
||||||
handleSD.isSDHC = 0;
|
|
||||||
handleSD.SDOPT = 0;
|
|
||||||
handleSD.res = 0;
|
|
||||||
handleSD.initarg = 0;
|
|
||||||
handleSD.clk = 0x80;
|
|
||||||
handleSD.devicenumber = 0;
|
|
||||||
|
|
||||||
*(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
|
||||||
*(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
|
||||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
|
||||||
*(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
|
|
||||||
*(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
|
|
||||||
*(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
|
|
||||||
*(vu16*)0x10006104 = 0; //SDBLKLEN32
|
|
||||||
*(vu16*)0x10006108 = 1; //SDBLKCOUNT32
|
|
||||||
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
|
|
||||||
*(vu16*)0x100060E0 |= 1u; //SDRESET
|
|
||||||
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
|
||||||
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
|
||||||
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
|
||||||
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
|
||||||
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
|
|
||||||
*(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
|
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
|
||||||
*(vu16*)0x10006026 = 512; //SDBLKLEN
|
|
||||||
*(vu16*)0x10006008 = 0; //SDSTOP
|
|
||||||
|
|
||||||
inittarget(&handleSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int SD_Init()
|
|
||||||
{
|
|
||||||
inittarget(&handleSD);
|
|
||||||
|
|
||||||
ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems
|
|
||||||
|
|
||||||
//If not inserted
|
|
||||||
if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0,0);
|
|
||||||
sdmmc_send_command(&handleSD,0x10408,0x1AA);
|
|
||||||
//u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
|
|
||||||
u32 temp = (handleSD.error & 0x1) << 0x1E;
|
|
||||||
|
|
||||||
//int count = 0;
|
|
||||||
u32 temp2 = 0;
|
|
||||||
do {
|
|
||||||
do {
|
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
|
||||||
sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
|
||||||
temp2 = 1;
|
|
||||||
} while ( !(handleSD.error & 1) );
|
|
||||||
|
|
||||||
} while((handleSD.ret[0] & 0x80000000) == 0);
|
|
||||||
|
|
||||||
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
|
|
||||||
temp2 = 0;
|
|
||||||
|
|
||||||
handleSD.isSDHC = temp2;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10602,0);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10403,0);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
handleSD.initarg = handleSD.ret[0] >> 0x10;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
|
|
||||||
handleSD.clk = 1;
|
|
||||||
setckl(1);
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
handleSD.SDOPT = 1;
|
|
||||||
sdmmc_send_command(&handleSD,0x10446,0x2);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10410,0x200);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
handleSD.clk |= 0x200;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdmmc_sdcard_init()
|
|
||||||
{
|
|
||||||
InitSD();
|
|
||||||
SD_Init();
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#define SDMMC_BASE 0x10006000u
|
|
||||||
|
|
||||||
#define REG_SDCMD 0x00
|
|
||||||
#define REG_SDPORTSEL 0x02
|
|
||||||
#define REG_SDCMDARG 0x04
|
|
||||||
#define REG_SDCMDARG0 0x04
|
|
||||||
#define REG_SDCMDARG1 0x06
|
|
||||||
#define REG_SDSTOP 0x08
|
|
||||||
#define REG_SDBLKCOUNT 0x0a
|
|
||||||
|
|
||||||
#define REG_SDRESP0 0x0c
|
|
||||||
#define REG_SDRESP1 0x0e
|
|
||||||
#define REG_SDRESP2 0x10
|
|
||||||
#define REG_SDRESP3 0x12
|
|
||||||
#define REG_SDRESP4 0x14
|
|
||||||
#define REG_SDRESP5 0x16
|
|
||||||
#define REG_SDRESP6 0x18
|
|
||||||
#define REG_SDRESP7 0x1a
|
|
||||||
|
|
||||||
#define REG_SDSTATUS0 0x1c
|
|
||||||
#define REG_SDSTATUS1 0x1e
|
|
||||||
|
|
||||||
#define REG_SDIRMASK0 0x20
|
|
||||||
#define REG_SDIRMASK1 0x22
|
|
||||||
#define REG_SDCLKCTL 0x24
|
|
||||||
|
|
||||||
#define REG_SDBLKLEN 0x26
|
|
||||||
#define REG_SDOPT 0x28
|
|
||||||
#define REG_SDFIFO 0x30
|
|
||||||
|
|
||||||
#define REG_SDDATACTL 0xd8
|
|
||||||
#define REG_SDRESET 0xe0
|
|
||||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
|
||||||
|
|
||||||
#define REG_SDDATACTL32 0x100
|
|
||||||
#define REG_SDBLKLEN32 0x104
|
|
||||||
#define REG_SDBLKCOUNT32 0x108
|
|
||||||
#define REG_SDFIFO32 0x10C
|
|
||||||
|
|
||||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
|
||||||
#define REG_RESET_SDIO 0x1e0
|
|
||||||
|
|
||||||
#define TMIO_STAT0_CMDRESPEND 0x0001
|
|
||||||
#define TMIO_STAT0_DATAEND 0x0004
|
|
||||||
#define TMIO_STAT0_CARD_REMOVE 0x0008
|
|
||||||
#define TMIO_STAT0_CARD_INSERT 0x0010
|
|
||||||
#define TMIO_STAT0_SIGSTATE 0x0020
|
|
||||||
#define TMIO_STAT0_WRPROTECT 0x0080
|
|
||||||
#define TMIO_STAT0_CARD_REMOVE_A 0x0100
|
|
||||||
#define TMIO_STAT0_CARD_INSERT_A 0x0200
|
|
||||||
#define TMIO_STAT0_SIGSTATE_A 0x0400
|
|
||||||
#define TMIO_STAT1_CMD_IDX_ERR 0x0001
|
|
||||||
#define TMIO_STAT1_CRCFAIL 0x0002
|
|
||||||
#define TMIO_STAT1_STOPBIT_ERR 0x0004
|
|
||||||
#define TMIO_STAT1_DATATIMEOUT 0x0008
|
|
||||||
#define TMIO_STAT1_RXOVERFLOW 0x0010
|
|
||||||
#define TMIO_STAT1_TXUNDERRUN 0x0020
|
|
||||||
#define TMIO_STAT1_CMDTIMEOUT 0x0040
|
|
||||||
#define TMIO_STAT1_RXRDY 0x0100
|
|
||||||
#define TMIO_STAT1_TXRQ 0x0200
|
|
||||||
#define TMIO_STAT1_ILL_FUNC 0x2000
|
|
||||||
#define TMIO_STAT1_CMD_BUSY 0x4000
|
|
||||||
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
|
||||||
|
|
||||||
//Comes from TWLSDK mongoose.tef DWARF info
|
|
||||||
#define SDMC_NORMAL 0x00000000
|
|
||||||
#define SDMC_ERR_COMMAND 0x00000001
|
|
||||||
#define SDMC_ERR_CRC 0x00000002
|
|
||||||
#define SDMC_ERR_END 0x00000004
|
|
||||||
#define SDMC_ERR_TIMEOUT 0x00000008
|
|
||||||
#define SDMC_ERR_FIFO_OVF 0x00000010
|
|
||||||
#define SDMC_ERR_FIFO_UDF 0x00000020
|
|
||||||
#define SDMC_ERR_WP 0x00000040
|
|
||||||
#define SDMC_ERR_ABORT 0x00000080
|
|
||||||
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
|
|
||||||
#define SDMC_ERR_PARAM 0x00000200
|
|
||||||
#define SDMC_ERR_R1_STATUS 0x00000800
|
|
||||||
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
|
|
||||||
#define SDMC_ERR_RESET 0x00002000
|
|
||||||
#define SDMC_ERR_ILA 0x00004000
|
|
||||||
#define SDMC_ERR_INFO_DETECT 0x00008000
|
|
||||||
|
|
||||||
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
|
|
||||||
#define SDMC_STAT_ERR_CC 0x00100000
|
|
||||||
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
|
|
||||||
#define SDMC_STAT_ERR_CRC 0x00800000
|
|
||||||
#define SDMC_STAT_ERR_OTHER 0xf9c70008
|
|
||||||
|
|
||||||
#define TMIO_MASK_ALL 0x837f031d
|
|
||||||
|
|
||||||
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
|
||||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
|
||||||
|
|
||||||
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
|
||||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
|
||||||
|
|
||||||
typedef struct mmcdevice {
|
|
||||||
vu8* data;
|
|
||||||
u32 size;
|
|
||||||
u32 error;
|
|
||||||
u16 stat0;
|
|
||||||
u16 stat1;
|
|
||||||
u32 ret[4];
|
|
||||||
u32 initarg;
|
|
||||||
u32 isSDHC;
|
|
||||||
u32 clk;
|
|
||||||
u32 SDOPT;
|
|
||||||
u32 devicenumber;
|
|
||||||
u32 total_size; //size in sectors of the device
|
|
||||||
u32 res;
|
|
||||||
} mmcdevice;
|
|
||||||
|
|
||||||
void sdmmc_sdcard_init();
|
|
||||||
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
|
||||||
@@ -1,57 +1,38 @@
|
|||||||
#include "types.h"
|
/*
|
||||||
#include "buttons.h"
|
* This file is part of Luma3DS
|
||||||
#include "fatfs/ff.h"
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x23F00000
|
#include "memory.h"
|
||||||
#define LOAD_PAYLOAD(a) loadPayload(a "_*.bin")
|
#include "cache.h"
|
||||||
|
|
||||||
static u32 loadPayload(const char *pattern)
|
extern u32 payloadSize; //Defined in start.s
|
||||||
{
|
|
||||||
char path[30] = "/luma/payloads";
|
|
||||||
|
|
||||||
DIR dir;
|
|
||||||
FILINFO info;
|
|
||||||
|
|
||||||
FRESULT result = f_findfirst(&dir, &info, path, pattern);
|
|
||||||
|
|
||||||
f_closedir(&dir);
|
|
||||||
|
|
||||||
if(result != FR_OK || !info.fname[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
path[14] = '/';
|
|
||||||
u32 i;
|
|
||||||
for(i = 0; info.fname[i]; i++)
|
|
||||||
path[15 + i] = info.fname[i];
|
|
||||||
path[15 + i] = '\0';
|
|
||||||
|
|
||||||
FIL payload;
|
|
||||||
unsigned int br;
|
|
||||||
|
|
||||||
f_open(&payload, path, FA_READ);
|
|
||||||
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
|
|
||||||
f_close(&payload);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
FATFS fs;
|
void *payloadAddress = (void *)0x23F00000;
|
||||||
|
|
||||||
f_mount(&fs, "0:", 1);
|
memcpy(payloadAddress, (void *)0x24F00000, payloadSize);
|
||||||
|
|
||||||
//Get pressed buttons
|
//Ensure that all memory transfers have completed and that the caches have been flushed
|
||||||
u32 pressed = HID_PAD;
|
flushCaches();
|
||||||
|
|
||||||
if(((pressed & BUTTON_RIGHT) && LOAD_PAYLOAD("right")) ||
|
((void (*)())payloadAddress)();
|
||||||
((pressed & BUTTON_LEFT) && LOAD_PAYLOAD("left")) ||
|
|
||||||
((pressed & BUTTON_UP) && LOAD_PAYLOAD("up")) ||
|
|
||||||
((pressed & BUTTON_DOWN) && LOAD_PAYLOAD("down")) ||
|
|
||||||
((pressed & BUTTON_X) && LOAD_PAYLOAD("x")) ||
|
|
||||||
((pressed & BUTTON_Y) && LOAD_PAYLOAD("y")) ||
|
|
||||||
((pressed & BUTTON_R1) && LOAD_PAYLOAD("r")) ||
|
|
||||||
((pressed & BUTTON_SELECT) && LOAD_PAYLOAD("sel")) ||
|
|
||||||
LOAD_PAYLOAD("def"))
|
|
||||||
((void (*)())PAYLOAD_ADDRESS)();
|
|
||||||
}
|
}
|
||||||
37
loader/source/memory.c
Normal file
37
loader/source/memory.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
void memcpy(void *dest, const void *src, u32 size)
|
||||||
|
{
|
||||||
|
u8 *destc = (u8 *)dest;
|
||||||
|
const u8 *srcc = (const u8 *)src;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size; i++)
|
||||||
|
destc[i] = srcc[i];
|
||||||
|
}
|
||||||
32
loader/source/memory.h
Normal file
32
loader/source/memory.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void memcpy(void *dest, const void *src, u32 size);
|
||||||
@@ -1,11 +1,29 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
.section .text.start
|
.section .text.start
|
||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
@ Flush caches
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
|
|
||||||
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
|
||||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
|
||||||
|
|
||||||
b main
|
b main
|
||||||
|
|
||||||
|
.global payloadSize
|
||||||
|
payloadSize:
|
||||||
|
.word 0
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
|
|||||||
11
menuhax/menuhax.diff
Normal file
11
menuhax/menuhax.diff
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
int main (void) {
|
||||||
|
+ svcSleepThread(2500 * 1000000ULL);
|
||||||
|
if (brahma_init()) {
|
||||||
|
if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1)
|
||||||
|
goto error;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
.arm.little
|
.arm.little
|
||||||
|
|
||||||
.create "emunand.bin", 0
|
.create "build/emunand.bin", 0
|
||||||
.arm
|
.arm
|
||||||
nand_sd:
|
nand_sd:
|
||||||
; Original code that still needs to be executed.
|
; Original code that still needs to be executed.
|
||||||
@@ -43,4 +43,4 @@ nand_sd:
|
|||||||
sdmmc: .ascii "SDMC"
|
sdmmc: .ascii "SDMC"
|
||||||
nand_offset: .ascii "NAND" ; for rednand this should be 1
|
nand_offset: .ascii "NAND" ; for rednand this should be 1
|
||||||
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
|
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
|
||||||
.close
|
.close
|
||||||
119
patches/k11modules.s
Normal file
119
patches/k11modules.s
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
;
|
||||||
|
; This file is part of Luma3DS
|
||||||
|
; Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
; Notices displayed by works containing it.
|
||||||
|
;
|
||||||
|
|
||||||
|
; This is mainly Subv's code, big thanks to him.
|
||||||
|
|
||||||
|
.arm.little
|
||||||
|
|
||||||
|
.create "build/k11modules.bin", 0
|
||||||
|
.arm
|
||||||
|
; This code searches the sm module for a specific byte pattern and patches some of the instructions
|
||||||
|
; in the code to disable service access checks when calling srv:GetServiceHandle
|
||||||
|
|
||||||
|
; It also searches the fs module for archive access check code
|
||||||
|
|
||||||
|
; Save the registers we'll be using
|
||||||
|
; Register contents:
|
||||||
|
; r4: Pointer to a pointer to the exheader of the current NCCH
|
||||||
|
; r6: Constant 0
|
||||||
|
; SP + 0x80 - 0x7C: Pointer to the memory location where the NCCH text was loaded
|
||||||
|
|
||||||
|
; Save the value of sp
|
||||||
|
mov r0, sp
|
||||||
|
; Save the value of all registers
|
||||||
|
push {r0-r12}
|
||||||
|
|
||||||
|
ldr r0, [r0, #(0x80 - 0x7C)] ; Load the .text address
|
||||||
|
ldr r7, [r4]
|
||||||
|
ldr r2, [r7, #0x18] ; Load the size of the .text
|
||||||
|
ldr r8, [r7, #0x200] ; Load the low title id of the current NCCH
|
||||||
|
mov r5, r0
|
||||||
|
add r11, r5, r2 ; Max bounds of the memory region
|
||||||
|
|
||||||
|
ldr r9, =0x00001002 ; Low title id of the sm module
|
||||||
|
cmp r8, r9 ; Compare the low title id to the id of the sm module
|
||||||
|
bne fs_patch ; Skip if they're not the same
|
||||||
|
|
||||||
|
ldr r7, =0xE1A01006 ; mov r1, r6
|
||||||
|
ldr r8, =0xE1A00005 ; mov r0, r5
|
||||||
|
ldr r9, =0xE3500000 ; cmp r0, #0
|
||||||
|
ldr r10, =0xE2850004 ; add r0, r5, #4
|
||||||
|
|
||||||
|
loop:
|
||||||
|
cmp r11, r5
|
||||||
|
blo out ; Check if we didn't go past the bounds of the memory region
|
||||||
|
ldr r6, [r5]
|
||||||
|
cmp r6, r7
|
||||||
|
ldreq r6, [r5, #4]
|
||||||
|
cmpeq r6, r8
|
||||||
|
ldreq r6, [r5, #12]
|
||||||
|
cmpeq r6, r9
|
||||||
|
ldreq r6, [r5, #24]
|
||||||
|
cmpeq r6, r10
|
||||||
|
moveq r8, r5
|
||||||
|
addne r5, r5, #4
|
||||||
|
bne loop
|
||||||
|
|
||||||
|
; r8 now contains the start address of the pattern we found
|
||||||
|
|
||||||
|
; Write NOPs to the four instructions we want to patch
|
||||||
|
ldr r9, =0xE320F000 ; nop
|
||||||
|
str r9, [r8, #8] ; Patch the bl
|
||||||
|
str r9, [r8, #12] ; Patch the cmp
|
||||||
|
str r9, [r8, #16] ; Patch the ldreq
|
||||||
|
str r9, [r8, #20] ; Patch the beq
|
||||||
|
b out
|
||||||
|
|
||||||
|
fs_patch: ; patch adapted from BootNTR
|
||||||
|
ldr r9, =0x00001102 ; Low title id of the fs module
|
||||||
|
cmp r8, r9 ; Compare the low title id to the id of the sm module
|
||||||
|
bne out ; Skip if they're not the same
|
||||||
|
|
||||||
|
ldr r7, =0x4618 ; mov r0, r3
|
||||||
|
ldr r8, =0x3481 ; add r4, #0x81
|
||||||
|
|
||||||
|
loop_fs:
|
||||||
|
cmp r11, r5
|
||||||
|
blo out
|
||||||
|
ldrh r6, [r5]
|
||||||
|
cmp r6, r7
|
||||||
|
ldreqh r6, [r5, #2]
|
||||||
|
cmpeq r6, r8
|
||||||
|
subeq r8, r5, #8
|
||||||
|
addne r5, #2
|
||||||
|
bne loop_fs
|
||||||
|
|
||||||
|
; r8 now contains the start address of the pattern we found
|
||||||
|
ldr r9, =0x2001 ; mov r0, #1
|
||||||
|
ldr r10, =0x4770 ; bx lr
|
||||||
|
strh r9, [r8]
|
||||||
|
strh r10, [r8, #2]
|
||||||
|
|
||||||
|
out:
|
||||||
|
pop {r0-r12} ; Restore the registers we used
|
||||||
|
|
||||||
|
ldr r0, [r4] ; Execute the instruction we overwrote in our detour
|
||||||
|
|
||||||
|
bx lr ; Jump back to whoever called us
|
||||||
|
|
||||||
|
.pool
|
||||||
|
.close
|
||||||
122
patches/reboot.s
122
patches/reboot.s
@@ -1,14 +1,18 @@
|
|||||||
.arm.little
|
.arm.little
|
||||||
|
|
||||||
payload_addr equ 0x23F00000 ; Brahma payload address.
|
payload_addr equ 0x23F00000 ; Brahma payload address.
|
||||||
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeBrah supports).
|
||||||
|
|
||||||
.create "reboot.bin", 0
|
.create "build/reboot.bin", 0
|
||||||
.arm
|
.arm
|
||||||
; Interesting registers and locations to keep in mind, set before this code is ran:
|
; Interesting registers and locations to keep in mind, set just before this code is ran:
|
||||||
; - sp + 0x3A8 - 0x70: FIRM path in exefs.
|
; - r1: FIRM path in exefs.
|
||||||
; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
|
; - r7: pointer to file object
|
||||||
; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
|
; - *r7: vtable
|
||||||
|
; - *(vtable + 0x28): fread function
|
||||||
|
; - *(r7 + 8): file handle
|
||||||
|
|
||||||
|
mov r8, r1
|
||||||
|
|
||||||
pxi_wait_recv:
|
pxi_wait_recv:
|
||||||
ldr r2, =0x44846
|
ldr r2, =0x44846
|
||||||
@@ -41,23 +45,28 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
|||||||
|
|
||||||
read_payload:
|
read_payload:
|
||||||
; Read file
|
; Read file
|
||||||
mov r0, r7
|
mov r0, r7
|
||||||
adr r1, bytes_read
|
adr r1, bytes_read
|
||||||
ldr r2, =payload_addr
|
ldr r2, =payload_addr
|
||||||
cmp r4, #0
|
cmp r4, #0
|
||||||
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
||||||
moveq r3, payload_maxsize
|
moveq r3, payload_maxsize
|
||||||
ldr r6, [sp, #0x3A8-0x198]
|
ldr r6, [r7]
|
||||||
ldr r6, [r6, #0x28]
|
ldr r6, [r6, #0x28]
|
||||||
blx r6
|
blx r6
|
||||||
cmp r4, #0
|
cmp r4, #0
|
||||||
movne r4, #0
|
movne r4, #0
|
||||||
bne read_payload ; Go read the real payload.
|
bne read_payload ; Go read the real payload.
|
||||||
|
|
||||||
add r0, sp, #0x3A8 - 0x70
|
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
|
||||||
ldr r0, [r0, #0x27]
|
add r0, r8, 0x1A
|
||||||
ldr r1, =payload_addr + 4
|
add r1, r0, #0x10
|
||||||
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
|
ldr r2, =payload_addr + 4
|
||||||
|
copy_TID_low:
|
||||||
|
ldrh r3, [r0], #2
|
||||||
|
strh r3, [r2], #2
|
||||||
|
cmp r0, r1
|
||||||
|
blo copy_TID_low
|
||||||
|
|
||||||
; Set kernel state
|
; Set kernel state
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
@@ -69,7 +78,7 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
|||||||
goto_reboot:
|
goto_reboot:
|
||||||
; Jump to reboot code
|
; Jump to reboot code
|
||||||
ldr r0, =(kernelcode_start - goto_reboot - 12)
|
ldr r0, =(kernelcode_start - goto_reboot - 12)
|
||||||
add r0, pc
|
add r0, pc ; pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4)
|
||||||
swi 0x7B
|
swi 0x7B
|
||||||
|
|
||||||
die:
|
die:
|
||||||
@@ -78,71 +87,42 @@ payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
|||||||
bytes_read: .word 0
|
bytes_read: .word 0
|
||||||
fopen: .ascii "OPEN"
|
fopen: .ascii "OPEN"
|
||||||
.pool
|
.pool
|
||||||
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
|
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
|
||||||
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
dat_fname: .dcw "sdmc:/Luma3DS.dat"
|
dat_fname: .dcw "sdmc:/Luma3DS.dat"
|
||||||
.word 0
|
.word 0
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
kernelcode_start:
|
kernelcode_start:
|
||||||
; Set MPU settings
|
|
||||||
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
|
||||||
mrc p15, 0, r12, c2, c0, 1 ; icacheable
|
|
||||||
mrc p15, 0, r1, c3, c0, 0 ; write bufferable
|
|
||||||
mrc p15, 0, r2, c5, c0, 2 ; daccess
|
|
||||||
mrc p15, 0, r3, c5, c0, 3 ; iaccess
|
|
||||||
ldr r4, =0x18000035 ; 0x18000000 128M
|
|
||||||
bic r2, r2, #0xF0000 ; unprotect region 4
|
|
||||||
bic r3, r3, #0xF0000 ; unprotect region 4
|
|
||||||
orr r0, r0, #0x10 ; dcacheable region 4
|
|
||||||
orr r2, r2, #0x30000 ; region 4 r/w
|
|
||||||
orr r3, r3, #0x30000 ; region 4 r/w
|
|
||||||
orr r12, r12, #0x10 ; icacheable region 4
|
|
||||||
orr r1, r1, #0x10 ; write bufferable region 4
|
|
||||||
mcr p15, 0, r0, c2, c0, 0
|
|
||||||
mcr p15, 0, r12, c2, c0, 1
|
|
||||||
mcr p15, 0, r1, c3, c0, 0 ; write bufferable
|
|
||||||
mcr p15, 0, r2, c5, c0, 2 ; daccess
|
|
||||||
mcr p15, 0, r3, c5, c0, 3 ; iaccess
|
|
||||||
mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
|
|
||||||
|
|
||||||
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
; Disable MPU
|
||||||
mrc p15, 0, r1, c2, c0, 1 ; icacheable
|
|
||||||
mrc p15, 0, r2, c3, c0, 0 ; write bufferable
|
|
||||||
orr r0, r0, #0x20 ; dcacheable region 5
|
|
||||||
orr r1, r1, #0x20 ; icacheable region 5
|
|
||||||
orr r2, r2, #0x20 ; write bufferable region 5
|
|
||||||
mcr p15, 0, r0, c2, c0, 0 ; dcacheable
|
|
||||||
mcr p15, 0, r1, c2, c0, 1 ; icacheable
|
|
||||||
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
|
|
||||||
|
|
||||||
; Flush cache
|
|
||||||
mov r2, #0
|
|
||||||
mov r1, r2
|
|
||||||
flush_cache:
|
|
||||||
mov r0, #0
|
|
||||||
mov r3, r2, lsl #30
|
|
||||||
flush_cache_inner_loop:
|
|
||||||
orr r12, r3, r0, lsl#5
|
|
||||||
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
|
||||||
mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
|
|
||||||
add r0, #1
|
|
||||||
cmp r0, #0x20
|
|
||||||
bcc flush_cache_inner_loop
|
|
||||||
add r2, #1
|
|
||||||
cmp r2, #4
|
|
||||||
bcc flush_cache
|
|
||||||
|
|
||||||
; Enable MPU
|
|
||||||
ldr r0, =0x42078 ; alt vector select, enable itcm
|
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||||
mcr p15, 0, r0, c1, c0, 0
|
mcr p15, 0, r0, c1, c0, 0
|
||||||
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
|
|
||||||
mcr p15, 0, r1, c7, c6, 0 ; flush icache
|
; Clean and flush data cache
|
||||||
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
mov r1, #0 ; segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 ; line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 ; generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
|
||||||
|
add r0, #0x20 ; increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
||||||
|
|
||||||
|
; Flush instruction cache
|
||||||
|
mcr p15, 0, r1, c7, c5, 0
|
||||||
|
|
||||||
; Jump to payload
|
; Jump to payload
|
||||||
ldr r0, =payload_addr
|
ldr r0, =payload_addr
|
||||||
bx r0
|
bx r0
|
||||||
|
|
||||||
.pool
|
.pool
|
||||||
.close
|
.close
|
||||||
48
patches/svcGetCFWInfo.s
Normal file
48
patches/svcGetCFWInfo.s
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
;
|
||||||
|
; This file is part of Luma3DS
|
||||||
|
; Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
; Notices displayed by works containing it.
|
||||||
|
;
|
||||||
|
|
||||||
|
.arm.little
|
||||||
|
|
||||||
|
.create "build/svcGetCFWInfo.bin", 0
|
||||||
|
.arm
|
||||||
|
|
||||||
|
adr r1, infoStart
|
||||||
|
add r2, r0, #(infoEnd - infoStart)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldrb r3, [r1], #1
|
||||||
|
strbt r3, [r0], #1
|
||||||
|
cmp r0, r2
|
||||||
|
blo loop
|
||||||
|
|
||||||
|
mov r0, #0
|
||||||
|
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.pool
|
||||||
|
infoStart:
|
||||||
|
.ascii "LUMA" ; magic
|
||||||
|
.word 0 ; version
|
||||||
|
.word 0 ; truncated commit hash
|
||||||
|
.word 0 ; config
|
||||||
|
infoEnd:
|
||||||
|
.close
|
||||||
@@ -8,24 +8,23 @@ typedef uint8_t u8;
|
|||||||
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
|
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
|
||||||
{
|
{
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
//Preprocessing
|
|
||||||
int table[256];
|
int table[256];
|
||||||
|
|
||||||
|
//Preprocessing
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 256; ++i)
|
for(i = 0; i < 256; i++)
|
||||||
table[i] = patternSize + 1;
|
table[i] = patternSize;
|
||||||
for(i = 0; i < patternSize; ++i)
|
for(i = 0; i < patternSize - 1; i++)
|
||||||
table[patternc[i]] = patternSize - i;
|
table[patternc[i]] = patternSize - i - 1;
|
||||||
|
|
||||||
//Searching
|
//Searching
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
while(j <= size - patternSize)
|
while(j <= size - patternSize)
|
||||||
{
|
{
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
u8 c = startPos[j + patternSize - 1];
|
||||||
|
if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0)
|
||||||
return startPos + j;
|
return startPos + j;
|
||||||
j += table[startPos[j + patternSize]];
|
j += table[c];
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
40
pathchanger/pathchanger.py
Normal file
40
pathchanger/pathchanger.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Requires Python >= 3.2 or >= 2.7
|
||||||
|
|
||||||
|
# This is part of Luma3DS
|
||||||
|
|
||||||
|
__author__ = "TuxSH"
|
||||||
|
__copyright__ = "Copyright (c) 2016 TuxSH"
|
||||||
|
__license__ = "GPLv3"
|
||||||
|
__version__ = "v1.0"
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Changes the path to Luma3DS for reboot patches")
|
||||||
|
parser.add_argument("payload", help="Path to the Luma3DS payload")
|
||||||
|
parser.add_argument("new_path", help="New Luma3DS payload path")
|
||||||
|
args = parser.parse_args()
|
||||||
|
data = b""
|
||||||
|
|
||||||
|
if len(args.new_path) > 37:
|
||||||
|
raise SystemExit("The new payload path is too large (37 characters max.)")
|
||||||
|
|
||||||
|
with open(args.payload, "rb") as f: data = bytearray(f.read())
|
||||||
|
|
||||||
|
if len(data) == 0: raise SystemExit("Could not read {0}".format(args.payload))
|
||||||
|
|
||||||
|
if len(data) > 0x20000:
|
||||||
|
raise SystemExit("The input file is too large, are you sure you're using a Luma3DS payload?")
|
||||||
|
|
||||||
|
found_index = data.find("sdmc:/".encode("utf-16-le"))
|
||||||
|
|
||||||
|
if found_index == -1:
|
||||||
|
raise SystemExit("The pattern was not found, are you sure you're usinga a Luma3DS payload?")
|
||||||
|
|
||||||
|
namebuf = args.new_path.encode("utf-16-le")
|
||||||
|
namebuf += b'\x00' * (74 - len(namebuf))
|
||||||
|
|
||||||
|
data[found_index + 12 : found_index + 12 + 74] = namebuf
|
||||||
|
|
||||||
|
with open(args.payload, "wb+") as f: f.write(data)
|
||||||
BIN
pathchanger/prebuilt/Linux/pathchanger
Executable file
BIN
pathchanger/prebuilt/Linux/pathchanger
Executable file
Binary file not shown.
BIN
pathchanger/prebuilt/Mac OS X/pathchanger
Executable file
BIN
pathchanger/prebuilt/Mac OS X/pathchanger
Executable file
Binary file not shown.
BIN
pathchanger/prebuilt/Windows/pathchanger.exe
Executable file
BIN
pathchanger/prebuilt/Windows/pathchanger.exe
Executable file
Binary file not shown.
@@ -1,105 +0,0 @@
|
|||||||
#include "types.h"
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
|
||||||
u32 brightnessLevel = *(vu32 *)0x24F03008;
|
|
||||||
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
|
||||||
|
|
||||||
*(vu32 *)0x10141200 = 0x1007F;
|
|
||||||
*(vu32 *)0x10202014 = 0x00000001;
|
|
||||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
|
||||||
*(vu32 *)0x10202240 = brightness[brightnessLevel];
|
|
||||||
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
|
|
||||||
*(vu32 *)0x10202244 = 0x1023E;
|
|
||||||
*(vu32 *)0x10202A44 = 0x1023E;
|
|
||||||
|
|
||||||
// Top screen
|
|
||||||
*(vu32 *)0x10400400 = 0x000001c2;
|
|
||||||
*(vu32 *)0x10400404 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400408 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040040c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400410 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400414 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400418 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400420 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400424 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400428 = 0x00000002;
|
|
||||||
*(vu32 *)0x1040042c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400430 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400434 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400438 = 0x00000001;
|
|
||||||
*(vu32 *)0x1040043c = 0x00000002;
|
|
||||||
*(vu32 *)0x10400440 = 0x01960192;
|
|
||||||
*(vu32 *)0x10400444 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400448 = 0x00000000;
|
|
||||||
*(vu32 *)0x1040045C = 0x00f00190;
|
|
||||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400464 = 0x01920002;
|
|
||||||
*(vu32 *)0x10400468 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400470 = 0x80341;
|
|
||||||
*(vu32 *)0x10400474 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400478 = 0;
|
|
||||||
*(vu32 *)0x10400490 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040049C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
|
||||||
for(u32 i = 0; i < 256; i++)
|
|
||||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
|
||||||
|
|
||||||
// Bottom screen
|
|
||||||
*(vu32 *)0x10400500 = 0x000001c2;
|
|
||||||
*(vu32 *)0x10400504 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400508 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040050c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400510 = 0x000000cd;
|
|
||||||
*(vu32 *)0x10400514 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400518 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400520 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400524 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400528 = 0x00000052;
|
|
||||||
*(vu32 *)0x1040052c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400530 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400534 = 0x0000004f;
|
|
||||||
*(vu32 *)0x10400538 = 0x00000050;
|
|
||||||
*(vu32 *)0x1040053c = 0x00000052;
|
|
||||||
*(vu32 *)0x10400540 = 0x01980194;
|
|
||||||
*(vu32 *)0x10400544 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400548 = 0x00000011;
|
|
||||||
*(vu32 *)0x1040055C = 0x00f00140;
|
|
||||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400564 = 0x01920052;
|
|
||||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
|
||||||
*(vu32 *)0x10400570 = 0x80301;
|
|
||||||
*(vu32 *)0x10400574 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400578 = 0;
|
|
||||||
*(vu32 *)0x10400590 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040059C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
|
||||||
for(u32 i = 0; i < 256; i++)
|
|
||||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
|
||||||
|
|
||||||
*(vu32 *)0x10400468 = 0x18300000;
|
|
||||||
*(vu32 *)0x1040046c = 0x18300000;
|
|
||||||
*(vu32 *)0x10400494 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400498 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400568 = 0x18346500;
|
|
||||||
*(vu32 *)0x1040056c = 0x18346500;
|
|
||||||
|
|
||||||
//Set CakeBrah framebuffers
|
|
||||||
*((vu32 *)0x23FFFE00) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE04) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE08) = 0x18346500;
|
|
||||||
|
|
||||||
//Clear ARM11 entry offset
|
|
||||||
*arm11 = 0;
|
|
||||||
|
|
||||||
//Wait for the entry to be set
|
|
||||||
while(!*arm11);
|
|
||||||
|
|
||||||
//Jump to it
|
|
||||||
((void (*)())*arm11)();
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
.section .text.start
|
|
||||||
.align 4
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
@ Disable interrupts
|
|
||||||
CPSID aif
|
|
||||||
|
|
||||||
b main
|
|
||||||
|
|
||||||
.word 0
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
//Common data types
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef volatile u8 vu8;
|
|
||||||
typedef volatile u16 vu16;
|
|
||||||
typedef volatile u32 vu32;
|
|
||||||
typedef volatile u64 vu64;
|
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* buttons.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -7,9 +25,10 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
||||||
|
|
||||||
#define BUTTON_R1 (1 << 8)
|
#define BUTTON_R1 (1 << 8)
|
||||||
#define BUTTON_L1 (1 << 9)
|
#define BUTTON_L1 (1 << 9)
|
||||||
#define BUTTON_A 1
|
#define BUTTON_A (1 << 0)
|
||||||
#define BUTTON_B (1 << 1)
|
#define BUTTON_B (1 << 1)
|
||||||
#define BUTTON_X (1 << 10)
|
#define BUTTON_X (1 << 10)
|
||||||
#define BUTTON_Y (1 << 11)
|
#define BUTTON_Y (1 << 11)
|
||||||
@@ -19,9 +38,10 @@
|
|||||||
#define BUTTON_LEFT (1 << 5)
|
#define BUTTON_LEFT (1 << 5)
|
||||||
#define BUTTON_UP (1 << 6)
|
#define BUTTON_UP (1 << 6)
|
||||||
#define BUTTON_DOWN (1 << 7)
|
#define BUTTON_DOWN (1 << 7)
|
||||||
#define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
|
|
||||||
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
|
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||||
#define OVERRIDE_BUTTONS (BUTTON_B ^ 0xFFF)
|
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
|
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
|
||||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_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 MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
||||||
|
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START)
|
||||||
39
source/cache.h
Normal file
39
source/cache.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/***
|
||||||
|
The following functions flush the data cache, then waits for all memory transfers to be finished.
|
||||||
|
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
|
||||||
|
- rebooting
|
||||||
|
- powering down
|
||||||
|
- setting the ARM11 entrypoint to execute a function
|
||||||
|
- jumping to a payload
|
||||||
|
***/
|
||||||
|
|
||||||
|
void flushEntireDCache(void); //actually: "clean and flush"
|
||||||
|
void flushDCacheRange(void *startAddress, u32 size);
|
||||||
|
void flushEntireICache(void);
|
||||||
|
void flushICacheRange(void *startAddress, u32 size);
|
||||||
89
source/cache.s
Normal file
89
source/cache.s
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@ This file is part of Luma3DS
|
||||||
|
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
@
|
||||||
|
@ This program is free software: you can redistribute it and/or modify
|
||||||
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
@ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ (at your option) any later version.
|
||||||
|
@
|
||||||
|
@ This program is distributed in the hope that it will be useful,
|
||||||
|
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
@ GNU General Public License for more details.
|
||||||
|
@
|
||||||
|
@ You should have received a copy of the GNU General Public License
|
||||||
|
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
@
|
||||||
|
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
@ Notices displayed by works containing it.
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global flushEntireDCache
|
||||||
|
.type flushEntireDCache, %function
|
||||||
|
flushEntireDCache:
|
||||||
|
@ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
|
||||||
|
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||||
|
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||||
|
|
||||||
|
@ Implemented in bootROM at address 0xffff0830
|
||||||
|
mov r1, #0 @ segment counter
|
||||||
|
outer_loop:
|
||||||
|
mov r0, #0 @ line counter
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
orr r2, r1, r0 @ generate segment and line address
|
||||||
|
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||||
|
add r0, #0x20 @ increment to next line
|
||||||
|
cmp r0, #0x400
|
||||||
|
bne inner_loop
|
||||||
|
|
||||||
|
add r1, #0x40000000
|
||||||
|
cmp r1, #0
|
||||||
|
bne outer_loop
|
||||||
|
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushDCacheRange
|
||||||
|
.type flushDCacheRange, %function
|
||||||
|
flushDCacheRange:
|
||||||
|
@ Implemented in bootROM at address 0xffff08a0
|
||||||
|
add r1, r0, r1 @ end address
|
||||||
|
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||||
|
|
||||||
|
flush_dcache_range_loop:
|
||||||
|
mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
|
||||||
|
add r0, #0x20
|
||||||
|
cmp r0, r1
|
||||||
|
blo flush_dcache_range_loop
|
||||||
|
|
||||||
|
mov r0, #0
|
||||||
|
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushEntireICache
|
||||||
|
.type flushEntireICache, %function
|
||||||
|
flushEntireICache:
|
||||||
|
@ Implemented in bootROM at address 0xffff0ab4
|
||||||
|
mov r0, #0
|
||||||
|
mcr p15, 0, r0, c7, c5, 0
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global flushICacheRange
|
||||||
|
.type flushICacheRange, %function
|
||||||
|
flushICacheRange:
|
||||||
|
@ Implemented in bootROM at address 0xffff0ac0
|
||||||
|
add r1, r0, r1 @ end address
|
||||||
|
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||||
|
|
||||||
|
flush_icache_range_loop:
|
||||||
|
mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding
|
||||||
|
add r0, #0x20
|
||||||
|
cmp r0, r1
|
||||||
|
blo flush_icache_range_loop
|
||||||
|
|
||||||
|
bx lr
|
||||||
260
source/config.c
260
source/config.c
@@ -1,41 +1,181 @@
|
|||||||
/*
|
/*
|
||||||
* config.c
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utils.h"
|
#include "memory.h"
|
||||||
#include "screeninit.h"
|
|
||||||
#include "draw.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "draw.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
#include "pin.h"
|
||||||
|
|
||||||
void configureCFW(const char *configPath)
|
bool readConfig(void)
|
||||||
{
|
{
|
||||||
initScreens();
|
if(fileRead(&configData, CONFIG_PATH, sizeof(CfgData)) != sizeof(CfgData) ||
|
||||||
|
memcmp(configData.magic, "CONF", 4) != 0 ||
|
||||||
|
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
|
||||||
|
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
||||||
|
{
|
||||||
|
configData.config = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
return true;
|
||||||
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
|
}
|
||||||
|
|
||||||
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
|
void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
|
||||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
|
{
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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 & 0xFFFFFE00) | (configTemp & 0x1FF);
|
||||||
|
|
||||||
|
if(!fileWrite(&configData, CONFIG_PATH, sizeof(CfgData)))
|
||||||
|
error("Error writing the configuration file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void configMenu(bool oldPinStatus)
|
||||||
|
{
|
||||||
|
const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
||||||
|
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||||
|
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||||
|
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )"
|
||||||
|
#ifdef DEV
|
||||||
|
, "Dev. features: ErrDisp( ) UNITINFO( ) Off( )"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
||||||
"( ) Use SysNAND FIRM as default (A9LH-only)",
|
"( ) Use SysNAND FIRM if booting with R (A9LH)",
|
||||||
"( ) Force A9LH detection",
|
"( ) Enable region/language emu. and ext. .code",
|
||||||
"( ) Use second EmuNAND as default",
|
"( ) Show NAND or user string in System Settings",
|
||||||
"( ) Enable region/language emulation",
|
|
||||||
"( ) Use developer UNITINFO",
|
|
||||||
"( ) Show current NAND in System Settings",
|
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
"( ) Enable splash screen with no screen-init" };
|
"( ) Display splash screen before payloads"
|
||||||
|
#ifdef DEV
|
||||||
|
, "( ) Patch SVC/service/archive/ARM9 access"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *optionsDescription[] = { "Select the default EmuNAND.\n"
|
||||||
|
"It will booted with no directional pad\n"
|
||||||
|
"buttons pressed",
|
||||||
|
|
||||||
|
"Select the screen brightness",
|
||||||
|
|
||||||
|
"Activate a PIN lock.\n"
|
||||||
|
"The PIN will be asked each time\n"
|
||||||
|
"Luma3DS boots.\n"
|
||||||
|
"4, 6 or 8 digits can be selected.\n"
|
||||||
|
"The ABXY buttons and the directional\n"
|
||||||
|
"pad buttons can be used as keys",
|
||||||
|
|
||||||
|
"Select the New 3DS CPU mode.\n"
|
||||||
|
"It will be always enabled.\n"
|
||||||
|
"'Clock+L2' can cause issues with some\n"
|
||||||
|
"games",
|
||||||
|
#ifdef DEV
|
||||||
|
"Select the developer features.\n"
|
||||||
|
"'ErrDisp' displays debug information\n"
|
||||||
|
"on the 'An error has occurred' screen.\n"
|
||||||
|
"'UNITINFO' makes the console be always\n"
|
||||||
|
"detected as a development unit (which\n"
|
||||||
|
"breaks online features and allows\n"
|
||||||
|
"booting some developer software).\n"
|
||||||
|
"'Off' disables exception handlers\n"
|
||||||
|
"in FIRM",
|
||||||
|
#endif
|
||||||
|
"If enabled SysNAND will be launched on\n"
|
||||||
|
"boot. Otherwise, an EmuNAND will.\n"
|
||||||
|
"Hold L on boot to switch NAND.\n"
|
||||||
|
"To use a different EmuNAND from the\n"
|
||||||
|
"default, hold a directional pad button\n"
|
||||||
|
"(Up/Right/Down/Left equal EmuNANDs\n"
|
||||||
|
"1/2/3/4)",
|
||||||
|
|
||||||
|
"If enabled, when holding R on boot\n"
|
||||||
|
"EmuNAND will be booted with the\n"
|
||||||
|
"SysNAND FIRM. Otherwise, SysNAND will\n"
|
||||||
|
"be booted with an EmuNAND FIRM.\n"
|
||||||
|
"To use a different EmuNAND from the\n"
|
||||||
|
"default, hold a directional pad button\n"
|
||||||
|
"(Up/Right/Down/Left equal EmuNANDs\n"
|
||||||
|
"1/2/3/4)",
|
||||||
|
|
||||||
|
"Enable overriding the region and\n"
|
||||||
|
"language configuration and the usage\n"
|
||||||
|
"of patched code binaries for specific\n"
|
||||||
|
"games.\n"
|
||||||
|
"Also makes certain DLCs for\n"
|
||||||
|
"out-of-region games work.\n"
|
||||||
|
"Refer to the wiki for instructions",
|
||||||
|
|
||||||
|
"Show the currently booted NAND\n"
|
||||||
|
"(Sys = SysNAND, Emu = EmuNAND 1,\n"
|
||||||
|
"EmuX = EmuNAND X,\n"
|
||||||
|
"SysE = SysNAND with EmuNAND 1 FIRM,\n"
|
||||||
|
"SyEX = SysNAND with EmuNAND X FIRM,\n"
|
||||||
|
"EmXS = EmuNAND X with SysNAND FIRM)\n"
|
||||||
|
"or an user-defined custom string in\n"
|
||||||
|
"System Settings.\n"
|
||||||
|
"Refer to the wiki for instructions",
|
||||||
|
|
||||||
|
"Show the GBA boot screen when booting\n"
|
||||||
|
"GBA games",
|
||||||
|
|
||||||
|
"If enabled, the splash screen will be\n"
|
||||||
|
"displayed before booting payloads,\n"
|
||||||
|
"otherwise it will be displayed\n"
|
||||||
|
"afterwards.\n"
|
||||||
|
"Intended for splash screens that\n"
|
||||||
|
"display button hints"
|
||||||
|
#ifdef DEV
|
||||||
|
, "Disable SVC, service, archive and ARM9\n"
|
||||||
|
"exheader access checks"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
struct multiOption {
|
struct multiOption {
|
||||||
int posXs[4];
|
u32 posXs[4];
|
||||||
int posY;
|
u32 posY;
|
||||||
u32 enabled;
|
u32 enabled;
|
||||||
} multiOptions[] = {
|
} multiOptions[] = {
|
||||||
{ .posXs = {26, 31, 36, 41} },
|
{ .posXs = {19, 24, 29, 34} },
|
||||||
|
{ .posXs = {21, 26, 31, 36} },
|
||||||
|
{ .posXs = {14, 19, 24, 29} },
|
||||||
{ .posXs = {17, 26, 32, 44} }
|
{ .posXs = {17, 26, 32, 44} }
|
||||||
|
#ifdef DEV
|
||||||
|
, { .posXs = {23, 35, 43, 0} }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
//Calculate the amount of the various kinds of options and pre-select the first single one
|
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||||
@@ -45,8 +185,8 @@ void configureCFW(const char *configPath)
|
|||||||
selectedOption = multiOptionsAmount;
|
selectedOption = multiOptionsAmount;
|
||||||
|
|
||||||
struct singleOption {
|
struct singleOption {
|
||||||
int posY;
|
u32 posY;
|
||||||
u32 enabled;
|
bool enabled;
|
||||||
} singleOptions[singleOptionsAmount];
|
} singleOptions[singleOptionsAmount];
|
||||||
|
|
||||||
//Parse the existing options
|
//Parse the existing options
|
||||||
@@ -55,17 +195,25 @@ void configureCFW(const char *configPath)
|
|||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
singleOptions[i].enabled = CONFIG(i);
|
singleOptions[i].enabled = CONFIG(i);
|
||||||
|
|
||||||
|
initScreens();
|
||||||
|
|
||||||
|
drawString(CONFIG_TITLE, true, 10, 10, COLOR_TITLE);
|
||||||
|
drawString("Press A to select, START to save", true, 10, 30, COLOR_WHITE);
|
||||||
|
|
||||||
//Character to display a selected option
|
//Character to display a selected option
|
||||||
char selected = 'x';
|
char selected = 'x';
|
||||||
|
|
||||||
int endPos = 42;
|
u32 endPos = 42;
|
||||||
|
|
||||||
//Display all the multiple choice options in white
|
//Display all the multiple choice options in white
|
||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
{
|
{
|
||||||
multiOptions[i].posY = endPos + SPACING_Y;
|
if(!(i == NEWCPU && !isN3DS))
|
||||||
endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE);
|
{
|
||||||
drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
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;
|
endPos += SPACING_Y / 2;
|
||||||
@@ -75,11 +223,13 @@ void configureCFW(const char *configPath)
|
|||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
{
|
{
|
||||||
singleOptions[i].posY = endPos + SPACING_Y;
|
singleOptions[i].posY = endPos + SPACING_Y;
|
||||||
endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, color);
|
endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color);
|
||||||
if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, color);
|
if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color);
|
||||||
color = COLOR_WHITE;
|
color = COLOR_WHITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
||||||
|
|
||||||
u32 pressed = 0;
|
u32 pressed = 0;
|
||||||
|
|
||||||
//Boring configuration menu
|
//Boring configuration menu
|
||||||
@@ -99,10 +249,12 @@ void configureCFW(const char *configPath)
|
|||||||
switch(pressed)
|
switch(pressed)
|
||||||
{
|
{
|
||||||
case BUTTON_UP:
|
case BUTTON_UP:
|
||||||
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
|
if(!selectedOption) selectedOption = totalIndexes;
|
||||||
|
else selectedOption = (selectedOption == NEWCPU + 1 && !isN3DS) ? selectedOption - 2 : selectedOption - 1;
|
||||||
break;
|
break;
|
||||||
case BUTTON_DOWN:
|
case BUTTON_DOWN:
|
||||||
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
|
if(selectedOption == totalIndexes) selectedOption = 0;
|
||||||
|
else selectedOption = (selectedOption == NEWCPU - 1 && !isN3DS) ? selectedOption + 2 : selectedOption + 1;
|
||||||
break;
|
break;
|
||||||
case BUTTON_LEFT:
|
case BUTTON_LEFT:
|
||||||
selectedOption = 0;
|
selectedOption = 0;
|
||||||
@@ -119,23 +271,26 @@ void configureCFW(const char *configPath)
|
|||||||
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
||||||
if(oldSelectedOption < multiOptionsAmount)
|
if(oldSelectedOption < multiOptionsAmount)
|
||||||
{
|
{
|
||||||
drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
drawString(multiOptionsText[oldSelectedOption], true, 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
||||||
drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
drawCharacter(selected, true, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
||||||
drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
drawString(singleOptionsText[singleOldSelected], true, 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
||||||
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selectedOption < multiOptionsAmount)
|
if(selectedOption < multiOptionsAmount)
|
||||||
drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED);
|
drawString(multiOptionsText[selectedOption], true, 10, multiOptions[selectedOption].posY, COLOR_RED);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 singleSelected = selectedOption - multiOptionsAmount;
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||||
drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED);
|
drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearScreens(false, true);
|
||||||
|
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -143,40 +298,45 @@ void configureCFW(const char *configPath)
|
|||||||
if(selectedOption < multiOptionsAmount)
|
if(selectedOption < multiOptionsAmount)
|
||||||
{
|
{
|
||||||
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
||||||
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
||||||
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
|
multiOptions[selectedOption].enabled = (oldEnabled == 3 || !multiOptions[selectedOption].posXs[oldEnabled + 1]) ? 0 : oldEnabled + 1;
|
||||||
|
|
||||||
|
if(selectedOption == BRIGHTNESS) updateBrightness(multiOptions[BRIGHTNESS].enabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
||||||
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
||||||
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
if(oldEnabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].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'
|
//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)
|
if(selectedOption < multiOptionsAmount)
|
||||||
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
drawCharacter(selected, true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 singleSelected = selectedOption - multiOptionsAmount;
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||||
if(singleOptions[singleSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
if(singleOptions[singleSelected].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Preserve the last-used boot options (last 12 bits)
|
u32 oldPinLength = MULTICONFIG(PIN);
|
||||||
config &= 0x3F;
|
|
||||||
|
//Preserve the last-used boot options (first 9 bits)
|
||||||
|
configData.config &= 0x1FF;
|
||||||
|
|
||||||
//Parse and write the new configuration
|
//Parse and write the new configuration
|
||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
config |= multiOptions[i].enabled << (i * 2 + 6);
|
configData.config |= multiOptions[i].enabled << (i * 2 + 9);
|
||||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
config |= singleOptions[i].enabled << (i + 16);
|
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 21);
|
||||||
|
|
||||||
fileWrite(&config, configPath, 4);
|
if(MULTICONFIG(PIN) != 0) newPin(oldPinStatus && MULTICONFIG(PIN) == oldPinLength);
|
||||||
|
else if(oldPinStatus) fileDelete(PIN_PATH);
|
||||||
|
|
||||||
//Zero the last booted FIRM flag
|
//Wait for the pressed buttons to change
|
||||||
CFG_BOOTENV = 0;
|
while(HID_PAD & PIN_BUTTONS);
|
||||||
|
|
||||||
mcuReboot();
|
chrono(2);
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,85 @@
|
|||||||
/*
|
/*
|
||||||
* config.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
#define CONFIG(a) (((configData.config >> (a + 21)) & 1) != 0)
|
||||||
|
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 9)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
|
||||||
|
|
||||||
#define CONFIG(a) ((config >> (a + 16)) & 1)
|
#define CONFIG_PATH "/luma/config.bin"
|
||||||
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
|
#define CONFIG_VERSIONMAJOR 1
|
||||||
#define BOOTCONFIG(a, b) ((config >> a) & b)
|
#define CONFIG_VERSIONMINOR 4
|
||||||
|
|
||||||
extern u32 config;
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
|
#define BOOTCFG_A9LH BOOTCONFIG(6, 1)
|
||||||
|
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
|
||||||
|
#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
|
||||||
|
|
||||||
void configureCFW(const char *configPath);
|
enum multiOptions
|
||||||
|
{
|
||||||
|
DEFAULTEMU = 0,
|
||||||
|
BRIGHTNESS,
|
||||||
|
PIN,
|
||||||
|
NEWCPU
|
||||||
|
#ifdef DEV
|
||||||
|
, DEVOPTIONS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum singleOptions
|
||||||
|
{
|
||||||
|
AUTOBOOTSYS = 0,
|
||||||
|
USESYSFIRM,
|
||||||
|
USELANGEMUANDCODE,
|
||||||
|
PATCHVERSTRING,
|
||||||
|
SHOWGBABOOT,
|
||||||
|
PAYLOADSPLASH
|
||||||
|
#ifdef DEV
|
||||||
|
, PATCHACCESS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
char magic[4];
|
||||||
|
u16 formatVersionMajor, formatVersionMinor;
|
||||||
|
|
||||||
|
u32 config;
|
||||||
|
} CfgData;
|
||||||
|
|
||||||
|
typedef enum ConfigurationStatus
|
||||||
|
{
|
||||||
|
DONT_CONFIGURE = 0,
|
||||||
|
MODIFY_CONFIGURATION,
|
||||||
|
CREATE_CONFIGURATION
|
||||||
|
} ConfigurationStatus;
|
||||||
|
|
||||||
|
extern CfgData configData;
|
||||||
|
extern bool isN3DS;
|
||||||
|
|
||||||
|
bool readConfig(void);
|
||||||
|
void writeConfig(ConfigurationStatus needConfig, u32 configTemp);
|
||||||
|
void configMenu(bool oldPinStatus);
|
||||||
506
source/crypto.c
506
source/crypto.c
@@ -1,7 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* crypto.c
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
*
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Crypto libs from http://github.com/b1l1s/ctr
|
* Crypto libs from http://github.com/b1l1s/ctr
|
||||||
|
* ARM9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
@@ -9,290 +30,291 @@
|
|||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Crypto Libs
|
* Crypto libs
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
/* original version by megazig */
|
/* original version by megazig */
|
||||||
|
|
||||||
#ifndef __thumb__
|
#ifndef __thumb__
|
||||||
#define BSWAP32(x) {\
|
#define BSWAP32(x) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"eor r1, %1, %1, ror #16\n\t"\
|
"eor r1, %1, %1, ror #16\n\t"\
|
||||||
"bic r1, r1, #0xFF0000\n\t"\
|
"bic r1, r1, #0xFF0000\n\t"\
|
||||||
"mov %0, %1, ror #8\n\t"\
|
"mov %0, %1, ror #8\n\t"\
|
||||||
"eor %0, %0, r1, lsr #8\n\t"\
|
"eor %0, %0, r1, lsr #8\n\t"\
|
||||||
:"=r"(x)\
|
:"=r"(x)\
|
||||||
:"0"(x)\
|
:"0"(x)\
|
||||||
:"r1"\
|
:"r1"\
|
||||||
);\
|
);\
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"adds %0, %4\n\t"\
|
"adds %0, %4\n\t"\
|
||||||
"addcss %1, %1, #1\n\t"\
|
"addcss %1, %1, #1\n\t"\
|
||||||
"addcss %2, %2, #1\n\t"\
|
"addcss %2, %2, #1\n\t"\
|
||||||
"addcs %3, %3, #1\n\t"\
|
"addcs %3, %3, #1\n\t"\
|
||||||
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
||||||
: "r"(u32_0)\
|
: "r"(u32_0)\
|
||||||
: "cc"\
|
: "cc"\
|
||||||
);\
|
);\
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define BSWAP32(x) {x = __builtin_bswap32(x);}
|
#define BSWAP32(x) {x = __builtin_bswap32(x);}
|
||||||
|
|
||||||
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
|
||||||
__asm__\
|
__asm__\
|
||||||
(\
|
(\
|
||||||
"mov r4, #0\n\t"\
|
"mov r4, #0\n\t"\
|
||||||
"add %0, %0, %4\n\t"\
|
"add %0, %0, %4\n\t"\
|
||||||
"adc %1, %1, r4\n\t"\
|
"adc %1, %1, r4\n\t"\
|
||||||
"adc %2, %2, r4\n\t"\
|
"adc %2, %2, r4\n\t"\
|
||||||
"adc %3, %3, r4\n\t"\
|
"adc %3, %3, r4\n\t"\
|
||||||
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
|
||||||
: "r"(u32_0)\
|
: "r"(u32_0)\
|
||||||
: "cc", "r4"\
|
: "cc", "r4"\
|
||||||
);\
|
);\
|
||||||
}
|
}
|
||||||
#endif /*__thumb__*/
|
#endif /*__thumb__*/
|
||||||
|
|
||||||
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
|
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
|
||||||
{
|
{
|
||||||
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
if(keyslot <= 0x03) return; // Ignore TWL keys for now
|
||||||
u32 *key32 = (u32 *)key;
|
u32 *key32 = (u32 *)key;
|
||||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||||
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
|
||||||
|
|
||||||
REG_AESKEYFIFO[keyType] = key32[0];
|
REG_AESKEYFIFO[keyType] = key32[0];
|
||||||
REG_AESKEYFIFO[keyType] = key32[1];
|
REG_AESKEYFIFO[keyType] = key32[1];
|
||||||
REG_AESKEYFIFO[keyType] = key32[2];
|
REG_AESKEYFIFO[keyType] = key32[2];
|
||||||
REG_AESKEYFIFO[keyType] = key32[3];
|
REG_AESKEYFIFO[keyType] = key32[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_use_keyslot(u8 keyslot)
|
static void aes_use_keyslot(u8 keyslot)
|
||||||
{
|
{
|
||||||
if(keyslot > 0x3F)
|
if(keyslot > 0x3F)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
*REG_AESKEYSEL = keyslot;
|
*REG_AESKEYSEL = keyslot;
|
||||||
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
|
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_setiv(const void *iv, u32 mode)
|
static void aes_setiv(const void *iv, u32 mode)
|
||||||
{
|
{
|
||||||
const u32 *iv32 = (const u32 *)iv;
|
const u32 *iv32 = (const u32 *)iv;
|
||||||
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
|
||||||
|
|
||||||
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
|
// Word order for IV can't be changed in REG_AESCNT and always default to reversed
|
||||||
if(mode & AES_INPUT_NORMAL)
|
if(mode & AES_INPUT_NORMAL)
|
||||||
{
|
{
|
||||||
REG_AESCTR[0] = iv32[3];
|
REG_AESCTR[0] = iv32[3];
|
||||||
REG_AESCTR[1] = iv32[2];
|
REG_AESCTR[1] = iv32[2];
|
||||||
REG_AESCTR[2] = iv32[1];
|
REG_AESCTR[2] = iv32[1];
|
||||||
REG_AESCTR[3] = iv32[0];
|
REG_AESCTR[3] = iv32[0];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
REG_AESCTR[0] = iv32[0];
|
REG_AESCTR[0] = iv32[0];
|
||||||
REG_AESCTR[1] = iv32[1];
|
REG_AESCTR[1] = iv32[1];
|
||||||
REG_AESCTR[2] = iv32[2];
|
REG_AESCTR[2] = iv32[2];
|
||||||
REG_AESCTR[3] = iv32[3];
|
REG_AESCTR[3] = iv32[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_advctr(void *ctr, u32 val, u32 mode)
|
static void aes_advctr(void *ctr, u32 val, u32 mode)
|
||||||
{
|
{
|
||||||
u32 *ctr32 = (u32 *)ctr;
|
u32 *ctr32 = (u32 *)ctr;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
if(mode & AES_INPUT_BE)
|
if(mode & AES_INPUT_BE)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i) // Endian swap
|
for(i = 0; i < 4; ++i) // Endian swap
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode & AES_INPUT_NORMAL)
|
if(mode & AES_INPUT_NORMAL)
|
||||||
{
|
{
|
||||||
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
|
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
|
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode & AES_INPUT_BE)
|
if(mode & AES_INPUT_BE)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i) // Endian swap
|
for(i = 0; i < 4; ++i) // Endian swap
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
|
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
|
||||||
{
|
{
|
||||||
u32 *ctr32 = (u32 *)ctr;
|
u32 *ctr32 = (u32 *)ctr;
|
||||||
int i;
|
int i;
|
||||||
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
|
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
|
||||||
{
|
{
|
||||||
for(i = 0; i < 4; ++i)
|
for(i = 0; i < 4; ++i)
|
||||||
BSWAP32(ctr32[i]);
|
BSWAP32(ctr32[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
|
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
|
||||||
{
|
{
|
||||||
u32 temp = ctr32[0];
|
u32 temp = ctr32[0];
|
||||||
ctr32[0] = ctr32[3];
|
ctr32[0] = ctr32[3];
|
||||||
ctr32[3] = temp;
|
ctr32[3] = temp;
|
||||||
|
|
||||||
temp = ctr32[1];
|
temp = ctr32[1];
|
||||||
ctr32[1] = ctr32[2];
|
ctr32[1] = ctr32[2];
|
||||||
ctr32[2] = temp;
|
ctr32[2] = temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes_batch(void *dst, const void *src, u32 blockCount)
|
static void aes_batch(void *dst, const void *src, u32 blockCount)
|
||||||
{
|
{
|
||||||
*REG_AESBLKCNT = blockCount << 16;
|
*REG_AESBLKCNT = blockCount << 16;
|
||||||
*REG_AESCNT |= AES_CNT_START;
|
*REG_AESCNT |= AES_CNT_START;
|
||||||
|
|
||||||
const u32 *src32 = (const u32 *)src;
|
const u32 *src32 = (const u32 *)src;
|
||||||
u32 *dst32 = (u32 *)dst;
|
u32 *dst32 = (u32 *)dst;
|
||||||
|
|
||||||
u32 wbc = blockCount;
|
u32 wbc = blockCount;
|
||||||
u32 rbc = blockCount;
|
u32 rbc = blockCount;
|
||||||
|
|
||||||
while(rbc)
|
while(rbc)
|
||||||
{
|
{
|
||||||
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
|
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
|
||||||
{
|
{
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
*REG_AESWRFIFO = *src32++;
|
*REG_AESWRFIFO = *src32++;
|
||||||
wbc--;
|
wbc--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
|
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
|
||||||
{
|
{
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
*dst32++ = *REG_AESRDFIFO;
|
*dst32++ = *REG_AESRDFIFO;
|
||||||
rbc--;
|
rbc--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
||||||
{
|
{
|
||||||
*REG_AESCNT = mode |
|
*REG_AESCNT = mode |
|
||||||
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
||||||
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
|
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
|
||||||
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
|
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
|
||||||
|
|
||||||
u32 blocks;
|
u32 blocks;
|
||||||
while(blockCount != 0)
|
while(blockCount != 0)
|
||||||
{
|
{
|
||||||
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
|
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
|
||||||
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
|
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
|
||||||
aes_setiv(iv, ivMode);
|
aes_setiv(iv, ivMode);
|
||||||
|
|
||||||
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
|
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
|
||||||
|
|
||||||
// Save the last block for the next decryption CBC batch's iv
|
// Save the last block for the next decryption CBC batch's iv
|
||||||
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
|
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
|
||||||
{
|
{
|
||||||
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
||||||
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the current batch
|
// Process the current batch
|
||||||
aes_batch(dst, src, blocks);
|
aes_batch(dst, src, blocks);
|
||||||
|
|
||||||
// Save the last block for the next encryption CBC batch's iv
|
// Save the last block for the next encryption CBC batch's iv
|
||||||
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
|
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
|
||||||
{
|
{
|
||||||
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
||||||
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance counter for CTR mode
|
// Advance counter for CTR mode
|
||||||
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
|
else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
|
||||||
aes_advctr(iv, blocks, ivMode);
|
aes_advctr(iv, blocks, ivMode);
|
||||||
|
|
||||||
src += blocks * AES_BLOCK_SIZE;
|
src += blocks * AES_BLOCK_SIZE;
|
||||||
dst += blocks * AES_BLOCK_SIZE;
|
dst += blocks * AES_BLOCK_SIZE;
|
||||||
blockCount -= blocks;
|
blockCount -= blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha_wait_idle()
|
static void sha_wait_idle()
|
||||||
{
|
{
|
||||||
while(*REG_SHA_CNT & 1);
|
while(*REG_SHA_CNT & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha(void *res, const void *src, u32 size, u32 mode)
|
static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||||
{
|
{
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
||||||
|
|
||||||
const u32 *src32 = (const u32 *)src;
|
const u32 *src32 = (const u32 *)src;
|
||||||
int i;
|
int i;
|
||||||
while(size >= 0x40)
|
while(size >= 0x40)
|
||||||
{
|
{
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
for(i = 0; i < 4; ++i)
|
for(i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
*REG_SHA_INFIFO = *src32++;
|
*REG_SHA_INFIFO = *src32++;
|
||||||
}
|
}
|
||||||
|
|
||||||
size -= 0x40;
|
size -= 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
||||||
|
|
||||||
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
||||||
|
|
||||||
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
|
|
||||||
u32 hashSize = SHA_256_HASH_SIZE;
|
u32 hashSize = SHA_256_HASH_SIZE;
|
||||||
if(mode == SHA_224_MODE)
|
if(mode == SHA_224_MODE)
|
||||||
hashSize = SHA_224_HASH_SIZE;
|
hashSize = SHA_224_HASH_SIZE;
|
||||||
else if(mode == SHA_1_MODE)
|
else if(mode == SHA_1_MODE)
|
||||||
hashSize = SHA_1_HASH_SIZE;
|
hashSize = SHA_1_HASH_SIZE;
|
||||||
|
|
||||||
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Nand/FIRM Crypto stuff
|
* NAND/FIRM crypto
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
static u8 nandCTR[0x10],
|
static u8 __attribute__((aligned(4))) nandCTR[0x10];
|
||||||
nandSlot;
|
static u8 nandSlot;
|
||||||
|
|
||||||
static u32 fatStart;
|
static u32 fatStart;
|
||||||
|
|
||||||
//Initialize the CTRNAND crypto
|
//Initialize the CTRNAND crypto
|
||||||
void ctrNandInit(void)
|
void ctrNandInit(void)
|
||||||
{
|
{
|
||||||
u8 cid[0x10];
|
u8 __attribute__((aligned(4))) cid[0x10];
|
||||||
u8 shaSum[0x20];
|
u8 __attribute__((aligned(4))) shaSum[0x20];
|
||||||
|
|
||||||
sdmmc_get_cid(1, (u32 *)cid);
|
sdmmc_get_cid(1, (u32 *)cid);
|
||||||
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
||||||
memcpy(nandCTR, shaSum, 0x10);
|
memcpy(nandCTR, shaSum, 0x10);
|
||||||
|
|
||||||
if(console)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||||
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
nandSlot = 0x05;
|
nandSlot = 0x05;
|
||||||
fatStart = 0x5CAD7;
|
fatStart = 0x5CAD7;
|
||||||
}
|
}
|
||||||
@@ -306,13 +328,13 @@ void ctrNandInit(void)
|
|||||||
//Read and decrypt from the selected CTRNAND
|
//Read and decrypt from the selected CTRNAND
|
||||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||||
{
|
{
|
||||||
u8 tmpCTR[0x10];
|
u8 __attribute__((aligned(4))) tmpCTR[0x10];
|
||||||
memcpy(tmpCTR, nandCTR, 0x10);
|
memcpy(tmpCTR, nandCTR, 0x10);
|
||||||
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
//Read
|
//Read
|
||||||
u32 result;
|
u32 result;
|
||||||
if(!firmSource)
|
if(firmSource == FIRMWARE_SYSNAND)
|
||||||
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -327,6 +349,24 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
|
||||||
|
void setRSAMod0DerivedKeys(void)
|
||||||
|
{
|
||||||
|
if(!isDevUnit)
|
||||||
|
{
|
||||||
|
const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
|
||||||
|
const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
|
||||||
|
|
||||||
|
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
|
||||||
|
when non-zero it clears this block and continues to do the key generation.
|
||||||
|
Otherwise when this block was already all-zero, it immediately returns. */
|
||||||
|
memset32((void *)0x01FFCD00, 0, 0x10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Decrypt a FIRM ExeFS
|
//Decrypt a FIRM ExeFS
|
||||||
void decryptExeFs(u8 *inbuf)
|
void decryptExeFs(u8 *inbuf)
|
||||||
{
|
{
|
||||||
@@ -345,12 +385,27 @@ void decryptExeFs(u8 *inbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ARM9Loader replacement
|
//ARM9Loader replacement
|
||||||
void arm9Loader(u8 *arm9Section, u32 mode)
|
void arm9Loader(u8 *arm9Section)
|
||||||
{
|
{
|
||||||
|
//Determine the arm9loader version
|
||||||
|
u32 a9lVersion;
|
||||||
|
switch(arm9Section[0x53])
|
||||||
|
{
|
||||||
|
case 0xFF:
|
||||||
|
a9lVersion = 0;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
a9lVersion = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
a9lVersion = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Firm keys
|
//Firm keys
|
||||||
u8 keyY[0x10];
|
u8 __attribute__((aligned(4))) keyY[0x10];
|
||||||
u8 arm9BinCTR[0x10];
|
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
|
||||||
u8 arm9BinSlot = mode ? 0x16 : 0x15;
|
u8 arm9BinSlot = a9lVersion != 0 ? 0x16 : 0x15;
|
||||||
|
|
||||||
//Setup keys needed for arm9bin decryption
|
//Setup keys needed for arm9bin decryption
|
||||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||||
@@ -359,16 +414,21 @@ void arm9Loader(u8 *arm9Section, u32 mode)
|
|||||||
//Calculate the size of the ARM9 binary
|
//Calculate the size of the ARM9 binary
|
||||||
u32 arm9BinSize = 0;
|
u32 arm9BinSize = 0;
|
||||||
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
||||||
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
for(u8 *tmp = arm9Section + 0x30; *tmp != 0; tmp++)
|
||||||
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
|
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
|
||||||
|
|
||||||
if(mode)
|
if(a9lVersion)
|
||||||
{
|
{
|
||||||
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
u8 __attribute__((aligned(4))) keyX[0x10];
|
||||||
u8 keyX[0x10];
|
|
||||||
|
if(!isDevUnit)
|
||||||
|
{
|
||||||
|
const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
|
||||||
|
const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
|
|
||||||
|
aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
//Set 0x11 to key2 for the arm9bin and misc keys
|
|
||||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
@@ -382,18 +442,28 @@ void arm9Loader(u8 *arm9Section, u32 mode)
|
|||||||
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
//Set >=9.6 KeyXs
|
//Set >=9.6 KeyXs
|
||||||
if(mode)
|
if(a9lVersion == 2 && !isDevUnit)
|
||||||
{
|
{
|
||||||
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
|
u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
|
||||||
u8 decKey[0x10];
|
u8 __attribute__((aligned(4))) decKey[0x10];
|
||||||
|
|
||||||
//Set keys 0x19..0x1F keyXs
|
//Set keys 0x19..0x1F keyXs
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
for(u8 slot = 0x19; slot < 0x20; slot++)
|
for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
|
||||||
{
|
{
|
||||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
keyData[0xF] += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void computePinHash(u8 *out, u8 *in)
|
||||||
|
{
|
||||||
|
u8 __attribute__((aligned(4))) cid[0x10];
|
||||||
|
u8 __attribute__((aligned(4))) cipherText[0x10];
|
||||||
|
|
||||||
|
sdmmc_get_cid(1, (u32 *)cid);
|
||||||
|
aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM
|
||||||
|
aes(cipherText, in, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
sha(out, cipherText, 0x10, SHA_256_MODE);
|
||||||
}
|
}
|
||||||
143
source/crypto.h
143
source/crypto.h
@@ -1,7 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* crypto.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
*
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Crypto libs from http://github.com/b1l1s/ctr
|
* Crypto libs from http://github.com/b1l1s/ctr
|
||||||
|
* ARM9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -9,79 +30,83 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
/**************************AES****************************/
|
/**************************AES****************************/
|
||||||
#define REG_AESCNT ((vu32 *)0x10009000)
|
#define REG_AESCNT ((vu32 *)0x10009000)
|
||||||
#define REG_AESBLKCNT ((vu32 *)0x10009004)
|
#define REG_AESBLKCNT ((vu32 *)0x10009004)
|
||||||
#define REG_AESWRFIFO ((vu32 *)0x10009008)
|
#define REG_AESWRFIFO ((vu32 *)0x10009008)
|
||||||
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
|
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
|
||||||
#define REG_AESKEYSEL ((vu8 *)0x10009010)
|
#define REG_AESKEYSEL ((vu8 *)0x10009010)
|
||||||
#define REG_AESKEYCNT ((vu8 *)0x10009011)
|
#define REG_AESKEYCNT ((vu8 *)0x10009011)
|
||||||
#define REG_AESCTR ((vu32 *)0x10009020)
|
#define REG_AESCTR ((vu32 *)0x10009020)
|
||||||
|
|
||||||
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
|
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
|
||||||
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
||||||
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
||||||
|
|
||||||
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
||||||
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
||||||
#define AES_CTR_MODE (2u << 27)
|
#define AES_CTR_MODE (2u << 27)
|
||||||
#define AES_CTR_MODE (2u << 27)
|
#define AES_CTR_MODE (2u << 27)
|
||||||
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
||||||
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
||||||
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
||||||
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
||||||
#define AES_ALL_MODES (7u << 27)
|
#define AES_ALL_MODES (7u << 27)
|
||||||
|
|
||||||
#define AES_CNT_START 0x80000000
|
#define AES_CNT_START 0x80000000
|
||||||
#define AES_CNT_INPUT_ORDER 0x02000000
|
#define AES_CNT_INPUT_ORDER 0x02000000
|
||||||
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
||||||
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
||||||
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
||||||
#define AES_CNT_FLUSH_READ 0x00000800
|
#define AES_CNT_FLUSH_READ 0x00000800
|
||||||
#define AES_CNT_FLUSH_WRITE 0x00000400
|
#define AES_CNT_FLUSH_WRITE 0x00000400
|
||||||
|
|
||||||
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
||||||
#define AES_INPUT_LE 0
|
#define AES_INPUT_LE 0
|
||||||
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
||||||
#define AES_INPUT_REVERSED 0
|
#define AES_INPUT_REVERSED 0
|
||||||
|
|
||||||
#define AES_BLOCK_SIZE 0x10
|
#define AES_BLOCK_SIZE 0x10
|
||||||
|
|
||||||
#define AES_KEYCNT_WRITE (1 << 0x7)
|
#define AES_KEYCNT_WRITE (1 << 0x7)
|
||||||
#define AES_KEYNORMAL 0
|
#define AES_KEYNORMAL 0
|
||||||
#define AES_KEYX 1
|
#define AES_KEYX 1
|
||||||
#define AES_KEYY 2
|
#define AES_KEYY 2
|
||||||
|
|
||||||
/**************************SHA****************************/
|
/**************************SHA****************************/
|
||||||
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
||||||
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
||||||
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
||||||
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
||||||
|
|
||||||
#define SHA_CNT_STATE 0x00000003
|
#define SHA_CNT_STATE 0x00000003
|
||||||
#define SHA_CNT_UNK2 0x00000004
|
#define SHA_CNT_UNK2 0x00000004
|
||||||
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||||
#define SHA_CNT_MODE 0x00000030
|
#define SHA_CNT_MODE 0x00000030
|
||||||
#define SHA_CNT_ENABLE 0x00010000
|
#define SHA_CNT_ENABLE 0x00010000
|
||||||
#define SHA_CNT_ACTIVE 0x00020000
|
#define SHA_CNT_ACTIVE 0x00020000
|
||||||
|
|
||||||
#define SHA_HASH_READY 0x00000000
|
#define SHA_HASH_READY 0x00000000
|
||||||
#define SHA_NORMAL_ROUND 0x00000001
|
#define SHA_NORMAL_ROUND 0x00000001
|
||||||
#define SHA_FINAL_ROUND 0x00000002
|
#define SHA_FINAL_ROUND 0x00000002
|
||||||
|
|
||||||
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||||
#define SHA_OUTPUT_LE 0
|
#define SHA_OUTPUT_LE 0
|
||||||
|
|
||||||
#define SHA_256_MODE 0
|
#define SHA_256_MODE 0
|
||||||
#define SHA_224_MODE 0x00000010
|
#define SHA_224_MODE 0x00000010
|
||||||
#define SHA_1_MODE 0x00000020
|
#define SHA_1_MODE 0x00000020
|
||||||
|
|
||||||
#define SHA_256_HASH_SIZE (256 / 8)
|
#define SHA_256_HASH_SIZE (256 / 8)
|
||||||
#define SHA_224_HASH_SIZE (224 / 8)
|
#define SHA_224_HASH_SIZE (224 / 8)
|
||||||
#define SHA_1_HASH_SIZE (160 / 8)
|
#define SHA_1_HASH_SIZE (160 / 8)
|
||||||
|
|
||||||
extern u32 emuOffset, console, firmSource;
|
extern u32 emuOffset;
|
||||||
|
extern bool isN3DS, isDevUnit;
|
||||||
|
extern FirmwareSource firmSource;
|
||||||
|
|
||||||
void ctrNandInit(void);
|
void ctrNandInit(void);
|
||||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||||
|
void setRSAMod0DerivedKeys(void);
|
||||||
void decryptExeFs(u8 *inbuf);
|
void decryptExeFs(u8 *inbuf);
|
||||||
void arm9Loader(u8 *arm9Section, u32 mode);
|
void arm9Loader(u8 *arm9Section);
|
||||||
|
void computePinHash(u8 *out, u8 *in);
|
||||||
@@ -1,64 +1,71 @@
|
|||||||
/*
|
/*
|
||||||
* draw.c
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
*
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Code to print to the screen by mid-kid @CakesFW
|
* Code to print to the screen by mid-kid @CakesFW
|
||||||
|
* https://github.com/mid-kid/CakesForeveryWan
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "strings.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "utils.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "memory.h"
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
#define SCREEN_TOP_WIDTH 400
|
bool loadSplash(void)
|
||||||
#define SCREEN_TOP_HEIGHT 240
|
|
||||||
|
|
||||||
static const struct fb {
|
|
||||||
u8 *top_left;
|
|
||||||
u8 *top_right;
|
|
||||||
u8 *bottom;
|
|
||||||
} *const fb = (struct fb *)0x23FFFE00;
|
|
||||||
|
|
||||||
static inline int strlen(const char *string)
|
|
||||||
{
|
{
|
||||||
char *stringEnd = (char *)string;
|
const char topSplashPath[] = "/luma/splash.bin",
|
||||||
while(*stringEnd) stringEnd++;
|
bottomSplashPath[] = "/luma/splashbottom.bin";
|
||||||
|
|
||||||
return stringEnd - string;
|
bool isTopSplashValid = getFileSize(topSplashPath) == SCREEN_TOP_FBSIZE,
|
||||||
}
|
isBottomSplashValid = getFileSize(bottomSplashPath) == SCREEN_BOTTOM_FBSIZE;
|
||||||
|
|
||||||
void clearScreens(void)
|
//Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD
|
||||||
{
|
if(!isTopSplashValid && !isBottomSplashValid)
|
||||||
memset32(fb->top_left, 0, 0x46500);
|
return false;
|
||||||
memset32(fb->top_right, 0, 0x46500);
|
|
||||||
memset32(fb->bottom, 0, 0x38400);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadSplash(void)
|
|
||||||
{
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
//Don't delay boot if no splash image is on the SD
|
if(isTopSplashValid) fileRead(fb->top_left, topSplashPath, 0);
|
||||||
if(fileRead(fb->top_left, "/luma/splash.bin", 0x46500) +
|
if(isBottomSplashValid) fileRead(fb->bottom, bottomSplashPath, 0);
|
||||||
fileRead(fb->bottom, "/luma/splashbottom.bin", 0x38400))
|
|
||||||
{
|
chrono(3);
|
||||||
u64 i = 0x1400000;
|
|
||||||
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color)
|
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color)
|
||||||
{
|
{
|
||||||
u8 *const select = fb->top_left;
|
u8 *select = isTopScreen ? fb->top_left : fb->bottom;
|
||||||
|
|
||||||
for(int y = 0; y < 8; y++)
|
for(u32 y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
char charPos = font[character * 8 + y];
|
char charPos = font[character * 8 + y];
|
||||||
|
|
||||||
for(int x = 7; x >= 0; x--)
|
for(u32 x = 0; x < 8; x++)
|
||||||
if ((charPos >> x) & 1)
|
if(((charPos >> (7 - x)) & 1) == 1)
|
||||||
{
|
{
|
||||||
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
|
u32 screenPos = (posX * SCREEN_HEIGHT * 3 + (SCREEN_HEIGHT - y - posY - 1) * 3) + x * 3 * SCREEN_HEIGHT;
|
||||||
|
|
||||||
select[screenPos] = color >> 16;
|
select[screenPos] = color >> 16;
|
||||||
select[screenPos + 1] = color >> 8;
|
select[screenPos + 1] = color >> 8;
|
||||||
@@ -67,9 +74,9 @@ void drawCharacter(char character, int posX, int posY, u32 color)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int drawString(const char *string, int posX, int posY, u32 color)
|
u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 color)
|
||||||
{
|
{
|
||||||
for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
|
for(u32 i = 0, line_i = 0; i < strlen(string); i++, line_i++)
|
||||||
{
|
{
|
||||||
if(string[i] == '\n')
|
if(string[i] == '\n')
|
||||||
{
|
{
|
||||||
@@ -77,15 +84,15 @@ int drawString(const char *string, int posX, int posY, u32 color)
|
|||||||
line_i = 0;
|
line_i = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
|
else if(line_i >= ((isTopScreen ? SCREEN_TOP_WIDTH : SCREEN_BOTTOM_WIDTH) - posX) / SPACING_X)
|
||||||
{
|
{
|
||||||
// Make sure we never get out of the screen.
|
//Make sure we never get out of the screen
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
line_i = 2; //Little offset so we know the same string continues.
|
line_i = 1; //Little offset so we know the same string continues
|
||||||
if(string[i] == ' ') i++; //Spaces at the start look weird
|
if(string[i] == ' ') i++; //Spaces at the start look weird
|
||||||
}
|
}
|
||||||
|
|
||||||
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
|
drawCharacter(string[i], isTopScreen, posX + line_i * SPACING_X, posY, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return posY;
|
return posY;
|
||||||
|
|||||||
@@ -1,21 +1,49 @@
|
|||||||
/*
|
/*
|
||||||
* draw.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
*
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
* Code to print to the screen by mid-kid @CakesFW
|
* Code to print to the screen by mid-kid @CakesFW
|
||||||
|
* https://github.com/mid-kid/CakesForeveryWan/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define SPACING_Y 10
|
#define SCREEN_TOP_WIDTH 400
|
||||||
#define SPACING_X 8
|
#define SCREEN_BOTTOM_WIDTH 320
|
||||||
#define COLOR_TITLE 0xFF9900
|
#define SCREEN_HEIGHT 240
|
||||||
#define COLOR_WHITE 0xFFFFFF
|
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||||
#define COLOR_RED 0x0000FF
|
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||||
#define COLOR_BLACK 0x000000
|
|
||||||
|
|
||||||
void loadSplash(void);
|
#define SPACING_Y 10
|
||||||
void clearScreens(void);
|
#define SPACING_X 8
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color);
|
|
||||||
int drawString(const char *string, int posX, int posY, u32 color);
|
#define COLOR_TITLE 0xFF9900
|
||||||
|
#define COLOR_WHITE 0xFFFFFF
|
||||||
|
#define COLOR_RED 0x0000FF
|
||||||
|
#define COLOR_BLACK 0x000000
|
||||||
|
#define COLOR_YELLOW 0x00FFFF
|
||||||
|
|
||||||
|
bool loadSplash(void);
|
||||||
|
void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color);
|
||||||
|
u32 drawString(const char *string, bool isTopScreen, u32 posX, u32 posY, u32 color);
|
||||||
182
source/emunand.c
182
source/emunand.c
@@ -1,78 +1,152 @@
|
|||||||
/*
|
/*
|
||||||
* emunand.c
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
#include "../build/emunandpatch.h"
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType)
|
||||||
{
|
{
|
||||||
static u8 *const temp = (u8 *)0x24300000;
|
static u8 temp[0x200];
|
||||||
|
|
||||||
const u32 nandSize = getMMCDevice(0)->total_size;
|
const u32 nandSize = getMMCDevice(0)->total_size;
|
||||||
u32 nandOffset = *emuNAND == 1 ? 0 :
|
bool found = false;
|
||||||
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
|
||||||
|
|
||||||
//Check for RedNAND
|
for(u32 i = 0; i < 3 && !found; i++)
|
||||||
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
|
|
||||||
{
|
{
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
u32 nandOffset;
|
||||||
|
switch(i)
|
||||||
{
|
{
|
||||||
*off = nandOffset + 1;
|
case 1:
|
||||||
*head = nandOffset + 1;
|
nandOffset = ROUND_TO_4MB(nandSize + 1); //"Default" layout
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
nandOffset = isN3DS ? 0x26E000 : 0x1D8000; //"Minsize" layout
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nandOffset = *nandType == FIRMWARE_EMUNAND ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //"Legacy" layout
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check for Gateway emuNAND
|
if(*nandType != FIRMWARE_EMUNAND) nandOffset *= ((u32)*nandType - 1);
|
||||||
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
|
|
||||||
{
|
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
|
||||||
{
|
|
||||||
*off = nandOffset;
|
|
||||||
*head = nandOffset + nandSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fallback to the first emuNAND if there's no second one,
|
//Check for RedNAND
|
||||||
or to SysNAND if there isn't any */
|
if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
else
|
{
|
||||||
{
|
emuOffset = nandOffset + 1;
|
||||||
(*emuNAND)--;
|
*emuHeader = nandOffset + 1;
|
||||||
if(*emuNAND) getEmunandSect(off, head, emuNAND);
|
found = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check for Gateway EmuNAND
|
||||||
|
else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
|
{
|
||||||
|
emuOffset = nandOffset;
|
||||||
|
*emuHeader = nandOffset + nandSize;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*nandType == FIRMWARE_EMUNAND) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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)
|
||||||
|
{
|
||||||
|
*nandType = FIRMWARE_EMUNAND;
|
||||||
|
locateEmuNand(emuHeader, nandType);
|
||||||
|
}
|
||||||
|
else *nandType = FIRMWARE_SYSNAND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getSDMMC(u8 *pos, u32 size)
|
static inline u8 *getFreeK9Space(u8 *pos, u32 size)
|
||||||
{
|
|
||||||
//Look for struct code
|
|
||||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
|
||||||
const u8 *off = memsearch(pos, pattern, size, 4) - 1;
|
|
||||||
|
|
||||||
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
|
|
||||||
{
|
|
||||||
//Look for read/write code
|
|
||||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
|
||||||
|
|
||||||
*readOff = (u32)memsearch(pos, pattern, size, 4) - 6;
|
|
||||||
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 *getMPU(u8 *pos, u32 size)
|
|
||||||
{
|
|
||||||
//Look for MPU pattern
|
|
||||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
|
||||||
|
|
||||||
return (u32 *)memsearch(pos, pattern, size, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *getEmuCode(u8 *proc9Offset)
|
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
//Looking for the last free space before Process9
|
//Looking for the last free space before Process9
|
||||||
return memsearch(proc9Offset - 0x3000, pattern, 0x3000, 6) + 0x455;
|
return memsearch(pos + 0x13500, pattern, size - 0x13500, sizeof(pattern)) + 0x455;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 getSdmmc(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
//Look for struct code
|
||||||
|
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||||
|
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
|
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
||||||
|
{
|
||||||
|
const u16 nandRedir[2] = {0x4C00, 0x47A0};
|
||||||
|
|
||||||
|
//Look for read/write code
|
||||||
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||||
|
|
||||||
|
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)) - 3,
|
||||||
|
*writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)) - 3;
|
||||||
|
|
||||||
|
*readOffset = nandRedir[0];
|
||||||
|
readOffset[1] = nandRedir[1];
|
||||||
|
((u32 *)readOffset)[1] = branchOffset;
|
||||||
|
*writeOffset = nandRedir[0];
|
||||||
|
writeOffset[1] = nandRedir[1];
|
||||||
|
((u32 *)writeOffset)[1] = branchOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void patchMpu(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
//Look for MPU pattern
|
||||||
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||||
|
|
||||||
|
u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
|
off[0] = 0x00360003;
|
||||||
|
off[6] = 0x00200603;
|
||||||
|
off[9] = 0x001C0603;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive)
|
||||||
|
{
|
||||||
|
//Copy EmuNAND code
|
||||||
|
u8 *freeK9Space = getFreeK9Space(arm9Section, arm9SectionSize);
|
||||||
|
memcpy(freeK9Space, emunand, emunand_size);
|
||||||
|
|
||||||
|
//Add the data of the found EmuNAND
|
||||||
|
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_size, 4),
|
||||||
|
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_size, 4);
|
||||||
|
*posOffset = emuOffset;
|
||||||
|
*posHeader = emuHeader;
|
||||||
|
|
||||||
|
//Find and add the SDMMC struct
|
||||||
|
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_size, 4);
|
||||||
|
*posSdmmc = getSdmmc(process9Offset, process9Size);
|
||||||
|
|
||||||
|
//Add EmuNAND hooks
|
||||||
|
u32 branchOffset = (u32)freeK9Space - branchAdditive;
|
||||||
|
patchNandRw(process9Offset, process9Size, branchOffset);
|
||||||
|
|
||||||
|
//Set MPU
|
||||||
|
patchMpu(arm9Section, arm9SectionSize);
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* emunand.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define NCSD_MAGIC (0x4453434E)
|
#define NCSD_MAGIC 0x4453434E
|
||||||
|
#define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1)))
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
|
extern u32 emuOffset;
|
||||||
u32 getSDMMC(u8 *pos, u32 size);
|
extern bool isN3DS;
|
||||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
|
|
||||||
u32 *getMPU(u8 *pos, u32 size);
|
void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType);
|
||||||
void *getEmuCode(u8 *proc9Offset);
|
void patchEmuNand(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive);
|
||||||
201
source/exceptions.c
Normal file
201
source/exceptions.c
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
#include "exceptions.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "../build/arm9_exceptions.h"
|
||||||
|
#include "../build/arm11_exceptions.h"
|
||||||
|
|
||||||
|
void installArm9Handlers(void)
|
||||||
|
{
|
||||||
|
const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
||||||
|
|
||||||
|
memcpy((void *)0x01FF8000, arm9_exceptions + 32, arm9_exceptions_size - 32);
|
||||||
|
|
||||||
|
/* IRQHandler is at 0x08000000, but we won't handle it for some reasons
|
||||||
|
svcHandler is at 0x08000010, but we won't handle svc either */
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
*(vu32 *)(0x08000000 + offsets[i]) = 0xE51FF004;
|
||||||
|
*(vu32 *)(0x08000000 + offsets[i] + 4) = *((u32 *)arm9_exceptions + 1 + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset)
|
||||||
|
{
|
||||||
|
u32 *initFPU;
|
||||||
|
for(initFPU = exceptionsPage; initFPU < (exceptionsPage + 0x400) && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU++);
|
||||||
|
|
||||||
|
u32 *mcuReboot;
|
||||||
|
for(mcuReboot = exceptionsPage; mcuReboot < (exceptionsPage + 0x400) && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot++);
|
||||||
|
mcuReboot--;
|
||||||
|
|
||||||
|
u32 *freeSpace;
|
||||||
|
for(freeSpace = initFPU; freeSpace < (exceptionsPage + 0x400) && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace++);
|
||||||
|
|
||||||
|
memcpy(freeSpace, arm11_exceptions + 32, arm11_exceptions_size - 32);
|
||||||
|
|
||||||
|
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 8) - 32); //Undefined Instruction
|
||||||
|
exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 12) - 32); //Prefetch Abort
|
||||||
|
exceptionsPage[4] = MAKE_BRANCH(exceptionsPage + 4, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 16) - 32); //Data Abort
|
||||||
|
exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 4) - 32); //FIQ
|
||||||
|
|
||||||
|
for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_size - 32); 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;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void detectAndProcessExceptionDumps(void)
|
||||||
|
{
|
||||||
|
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
|
||||||
|
|
||||||
|
if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[42];
|
||||||
|
char fileName[] = "crash_dump_00000000.dmp";
|
||||||
|
const char *pathFolder = dumpHeader->processor == 9 ? "/luma/dumps/arm9" : "/luma/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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
49
source/exceptions.h
Normal file
49
source/exceptions.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "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))
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
u32 magic[2];
|
||||||
|
u16 versionMinor, versionMajor;
|
||||||
|
|
||||||
|
u16 processor, core;
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
u32 totalSize;
|
||||||
|
u32 registerDumpSize;
|
||||||
|
u32 codeDumpSize;
|
||||||
|
u32 stackDumpSize;
|
||||||
|
u32 additionalDataSize;
|
||||||
|
} ExceptionDumpHeader;
|
||||||
|
|
||||||
|
void installArm9Handlers(void);
|
||||||
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset);
|
||||||
|
void detectAndProcessExceptionDumps(void);
|
||||||
|
#endif
|
||||||
33
source/fatfs/00history.txt
Normal file → Executable file
33
source/fatfs/00history.txt
Normal file → Executable file
@@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
|
|||||||
|
|
||||||
R0.01 (April 29, 2006)
|
R0.01 (April 29, 2006)
|
||||||
|
|
||||||
First stable version.
|
The first release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -246,9 +246,34 @@ R0.11a (September 05, 2015)
|
|||||||
|
|
||||||
R0.12 (April 12, 2016)
|
R0.12 (April 12, 2016)
|
||||||
|
|
||||||
Added support of exFAT file system. (_FS_EXFAT)
|
Added support for exFAT file system. (_FS_EXFAT)
|
||||||
Added f_expand(). (_USE_EXPAND)
|
Added f_expand(). (_USE_EXPAND)
|
||||||
Changed some members in FINFO structure and behavior of f_readdir().
|
Changed some members in FINFO structure and behavior of f_readdir().
|
||||||
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
|
Added an option _USE_CHMOD.
|
||||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
Removed an option _WORD_ACCESS.
|
||||||
|
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12a (July 10, 2016)
|
||||||
|
|
||||||
|
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||||
|
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||||
|
f_forward() is available regardless of _FS_TINY.
|
||||||
|
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||||
|
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||||
|
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12b (September 04, 2016)
|
||||||
|
|
||||||
|
Improved f_rename() to 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)
|
||||||
|
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||||
|
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||||
|
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)
|
||||||
|
|
||||||
|
|||||||
2
source/fatfs/00readme.txt
Normal file → Executable file
2
source/fatfs/00readme.txt
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
FatFs Module Source Files R0.12
|
FatFs Module Source Files R0.12a
|
||||||
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "sdmmc/sdmmc.h"
|
#include "sdmmc/sdmmc.h"
|
||||||
|
#include "../crypto.h"
|
||||||
|
|
||||||
/* Definitions of physical drive number for each media */
|
/* Definitions of physical drive number for each media */
|
||||||
#define SDCARD 0
|
#define SDCARD 0
|
||||||
|
|||||||
1698
source/fatfs/ff.c
Normal file → Executable file
1698
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
104
source/fatfs/ff.h
Normal file → Executable file
104
source/fatfs/ff.h
Normal file → Executable file
@@ -1,11 +1,13 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*----------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
|
/ FatFs - Generic FAT file system module R0.12b /
|
||||||
/----------------------------------------------------------------------------/
|
/-----------------------------------------------------------------------------/
|
||||||
/ FatFs module is a free software that opened under license policy of
|
|
||||||
/ following conditions.
|
|
||||||
/
|
/
|
||||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||||
/
|
/
|
||||||
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
|
/ that the following condition is met:
|
||||||
|
|
||||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||||
/ this condition and the following disclaimer.
|
/ this condition and the following disclaimer.
|
||||||
/
|
/
|
||||||
@@ -13,11 +15,11 @@
|
|||||||
/ and any warranties related to this software are DISCLAIMED.
|
/ and any warranties related to this software are DISCLAIMED.
|
||||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||||
/ by use of this software.
|
/ by use of this software.
|
||||||
/---------------------------------------------------------------------------*/
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
#ifndef _FATFS
|
||||||
#define _FATFS 88100 /* Revision ID */
|
#define _FATFS 68020 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -25,6 +27,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include "integer.h" /* Basic integer types */
|
#include "integer.h" /* Basic integer types */
|
||||||
#include "ffconf.h" /* FatFs configuration options */
|
#include "ffconf.h" /* FatFs configuration options */
|
||||||
|
|
||||||
#if _FATFS != _FFCONF
|
#if _FATFS != _FFCONF
|
||||||
#error Wrong configuration file (ffconf.h).
|
#error Wrong configuration file (ffconf.h).
|
||||||
#endif
|
#endif
|
||||||
@@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
|||||||
|
|
||||||
/* Type of path name strings on FatFs API */
|
/* Type of path name strings on FatFs API */
|
||||||
|
|
||||||
#if _LFN_UNICODE /* Unicode string */
|
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||||
#if _USE_LFN == 0
|
#if _USE_LFN == 0
|
||||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||||
#endif
|
#endif
|
||||||
@@ -61,14 +64,25 @@ typedef WCHAR TCHAR;
|
|||||||
#define _T(x) L ## x
|
#define _T(x) L ## x
|
||||||
#define _TEXT(x) L ## x
|
#define _TEXT(x) L ## x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* ANSI/OEM string */
|
#else /* ANSI/OEM string */
|
||||||
#ifndef _INC_TCHAR
|
#ifndef _INC_TCHAR
|
||||||
typedef char TCHAR;
|
typedef char TCHAR;
|
||||||
#define _T(x) x
|
#define _T(x) x
|
||||||
#define _TEXT(x) x
|
#define _TEXT(x) x
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of file size variables */
|
||||||
|
|
||||||
|
#if _FS_EXFAT
|
||||||
|
#if _USE_LFN == 0
|
||||||
|
#error LFN must be enabled when enable exFAT
|
||||||
|
#endif
|
||||||
|
typedef QWORD FSIZE_t;
|
||||||
|
#else
|
||||||
|
typedef DWORD FSIZE_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -87,6 +101,9 @@ typedef struct {
|
|||||||
#if _MAX_SS != _MIN_SS
|
#if _MAX_SS != _MIN_SS
|
||||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||||
#endif
|
#endif
|
||||||
|
#if _USE_LFN != 0
|
||||||
|
WCHAR* lfnbuf; /* LFN working buffer */
|
||||||
|
#endif
|
||||||
#if _FS_EXFAT
|
#if _FS_EXFAT
|
||||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||||
#endif
|
#endif
|
||||||
@@ -117,19 +134,6 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Type of file size variables and object identifier */
|
|
||||||
|
|
||||||
#if _FS_EXFAT
|
|
||||||
#if _USE_LFN == 0
|
|
||||||
#error LFN must be enabled when enable exFAT
|
|
||||||
#endif
|
|
||||||
typedef QWORD FSIZE_t;
|
|
||||||
#else
|
|
||||||
typedef DWORD FSIZE_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Object ID and allocation information (_FDID) */
|
/* Object ID and allocation information (_FDID) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -155,18 +159,18 @@ typedef struct {
|
|||||||
/* File object structure (FIL) */
|
/* File object structure (FIL) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
_FDID obj; /* Object identifier */
|
_FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||||
BYTE flag; /* File status flags */
|
BYTE flag; /* File status flags */
|
||||||
BYTE err; /* Abort flag (error code) */
|
BYTE err; /* Abort flag (error code) */
|
||||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||||
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||||
#if !_FS_READONLY
|
#if !_FS_READONLY
|
||||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FASTSEEK
|
#if _USE_FASTSEEK
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
#endif
|
#endif
|
||||||
#if !_FS_TINY
|
#if !_FS_TINY
|
||||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||||
@@ -183,10 +187,9 @@ typedef struct {
|
|||||||
DWORD clust; /* Current cluster */
|
DWORD clust; /* Current cluster */
|
||||||
DWORD sect; /* Current sector */
|
DWORD sect; /* Current sector */
|
||||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||||
BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
|
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||||
#if _USE_LFN != 0
|
#if _USE_LFN != 0
|
||||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
|
||||||
#endif
|
#endif
|
||||||
#if _USE_FIND
|
#if _USE_FIND
|
||||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||||
@@ -229,7 +232,7 @@ typedef enum {
|
|||||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
@@ -244,11 +247,11 @@ typedef enum {
|
|||||||
|
|
||||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
|
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||||
@@ -258,8 +261,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
|||||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
|
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
|
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||||
@@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
|||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
@@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
|||||||
/* Flags and offset address */
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
/* File access control and file status flags (FIL.flag) */
|
/* File access mode and open method flags (3rd argument of f_open) */
|
||||||
|
|
||||||
#define FA_READ 0x01
|
#define FA_READ 0x01
|
||||||
#define FA_WRITE 0x02
|
#define FA_WRITE 0x02
|
||||||
#define FA_OPEN_EXISTING 0x00
|
#define FA_OPEN_EXISTING 0x00
|
||||||
#define FA_CREATE_NEW 0x04
|
#define FA_CREATE_NEW 0x04
|
||||||
#define FA_CREATE_ALWAYS 0x08
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
#define FA_OPEN_ALWAYS 0x10
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
#define _FA_MODIFIED 0x20
|
#define FA_OPEN_APPEND 0x30
|
||||||
#define _FA_DIRTY 0x40
|
|
||||||
|
|
||||||
|
/* Fast seek controls (2nd argument of f_lseek) */
|
||||||
|
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||||
|
|
||||||
/* FAT sub type (FATFS.fs_type) */
|
/* Format options (2nd argument of f_mkfs) */
|
||||||
|
#define FM_FAT 0x01
|
||||||
|
#define FM_FAT32 0x02
|
||||||
|
#define FM_EXFAT 0x04
|
||||||
|
#define FM_ANY 0x07
|
||||||
|
#define FM_SFD 0x08
|
||||||
|
|
||||||
|
/* Filesystem type (FATFS.fs_type) */
|
||||||
#define FS_FAT12 1
|
#define FS_FAT12 1
|
||||||
#define FS_FAT16 2
|
#define FS_FAT16 2
|
||||||
#define FS_FAT32 3
|
#define FS_FAT32 3
|
||||||
#define FS_EXFAT 4
|
#define FS_EXFAT 4
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||||
/* File attribute bits for directory entry */
|
|
||||||
|
|
||||||
#define AM_RDO 0x01 /* Read only */
|
#define AM_RDO 0x01 /* Read only */
|
||||||
#define AM_HID 0x02 /* Hidden */
|
#define AM_HID 0x02 /* Hidden */
|
||||||
#define AM_SYS 0x04 /* System */
|
#define AM_SYS 0x04 /* System */
|
||||||
#define AM_VOL 0x08 /* Volume label */
|
|
||||||
#define AM_LFN 0x0F /* LFN entry */
|
|
||||||
#define AM_DIR 0x10 /* Directory */
|
#define AM_DIR 0x10 /* Directory */
|
||||||
#define AM_ARC 0x20 /* Archive */
|
#define AM_ARC 0x20 /* Archive */
|
||||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
|
||||||
|
|
||||||
|
|
||||||
/* Fast seek controls */
|
|
||||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
27
source/fatfs/ffconf.h
Normal file → Executable file
27
source/fatfs/ffconf.h
Normal file → Executable file
@@ -1,8 +1,8 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
|
/ FatFs - FAT file system module configuration file
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FFCONF 88100 /* Revision ID */
|
#define _FFCONF 68020 /* Revision ID */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ Function Configurations
|
/ Function Configurations
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
/ and optional writing functions as well. */
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 1
|
#define _FS_MINIMIZE 0
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
/
|
/
|
||||||
/ 0: All basic functions are enabled.
|
/ 0: All basic functions are enabled.
|
||||||
@@ -62,8 +62,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _USE_FORWARD 0
|
#define _USE_FORWARD 0
|
||||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||||
/ To enable it, also _FS_TINY need to be 1. */
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
@@ -118,13 +117,13 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _LFN_UNICODE 0
|
#define _LFN_UNICODE 0
|
||||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
|
||||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
||||||
/ This option also affects behavior of string I/O functions. */
|
/ This option also affects behavior of string I/O functions. */
|
||||||
|
|
||||||
|
|
||||||
#define _STRF_ENCODE 3
|
#define _STRF_ENCODE 3
|
||||||
/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to
|
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
|
||||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||||
/
|
/
|
||||||
/ 0: ANSI/OEM
|
/ 0: ANSI/OEM
|
||||||
@@ -153,7 +152,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define _STR_VOLUME_ID 0
|
#define _STR_VOLUME_ID 0
|
||||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||||
@@ -205,19 +204,19 @@
|
|||||||
|
|
||||||
#define _FS_TINY 0
|
#define _FS_TINY 0
|
||||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
|
/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.
|
||||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
/ 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. */
|
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_EXFAT 0
|
#define _FS_EXFAT 0
|
||||||
/* This option switches support of exFAT file system in addition to the traditional
|
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||||
/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
|
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||||
/ Note that enabling exFAT discards C89 compatibility. */
|
/ Note that enabling exFAT discards C89 compatibility. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_NORTC 1
|
#define _FS_NORTC 1
|
||||||
#define _NORTC_MON 3
|
#define _NORTC_MON 1
|
||||||
#define _NORTC_MDAY 1
|
#define _NORTC_MDAY 1
|
||||||
#define _NORTC_YEAR 2016
|
#define _NORTC_YEAR 2016
|
||||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||||
@@ -260,7 +259,9 @@
|
|||||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
/ 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*,
|
/ 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.c. */
|
/ included somewhere in the scope of ff.h. */
|
||||||
|
|
||||||
|
/* #include <windows.h> // O/S definitions */
|
||||||
|
|
||||||
|
|
||||||
/*--- End of configuration options ---*/
|
/*--- End of configuration options ---*/
|
||||||
|
|||||||
0
source/fatfs/integer.h
Normal file → Executable file
0
source/fatfs/integer.h
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
0
source/fatfs/option/ccsbcs.c
Normal file → Executable file
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "../../types.h"
|
|
||||||
#include "../../crypto.h"
|
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "../../types.h"
|
||||||
|
|
||||||
void ioDelay(u32 us);
|
void waitcycles(u32 us);
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
.arm
|
.arm
|
||||||
.global ioDelay
|
.global waitcycles
|
||||||
.type ioDelay STT_FUNC
|
.type waitcycles STT_FUNC
|
||||||
|
|
||||||
@ioDelay ( u32 us )
|
@waitcycles ( u32 us )
|
||||||
ioDelay:
|
waitcycles:
|
||||||
ldr r1, =0x18000000 @ VRAM
|
PUSH {R0-R2,LR}
|
||||||
1:
|
STR R0, [SP,#4]
|
||||||
@ Loop doing uncached reads from VRAM to make loop timing more reliable
|
waitcycles_loop:
|
||||||
ldr r2, [r1]
|
LDR R3, [SP,#4]
|
||||||
subs r0, #1
|
SUBS R2, R3, #1
|
||||||
bgt 1b
|
STR R2, [SP,#4]
|
||||||
bx lr
|
CMP R3, #0
|
||||||
|
BNE waitcycles_loop
|
||||||
|
POP {R0-R2,PC}
|
||||||
|
|||||||
@@ -1,30 +1,55 @@
|
|||||||
// Copyright 2014 Normmatt
|
/*
|
||||||
// Licensed under GPLv2 or any later version
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
// Refer to the license.txt file included.
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2015, Normmatt
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms
|
||||||
|
* of the GNU General Public License Version 2, as described below:
|
||||||
|
*
|
||||||
|
* This file is free software: you may copy, redistribute and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "delay.h"
|
#include "delay.h"
|
||||||
|
|
||||||
struct mmcdevice handleNAND;
|
static struct mmcdevice handleNAND;
|
||||||
struct mmcdevice handleSD;
|
static struct mmcdevice handleSD;
|
||||||
|
|
||||||
static inline u16 sdmmc_read16(u16 reg) {
|
static inline u16 sdmmc_read16(u16 reg)
|
||||||
return *(vu16*)(SDMMC_BASE + reg);
|
{
|
||||||
|
return *(vu16 *)(SDMMC_BASE + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_write16(u16 reg, u16 val) {
|
static inline void sdmmc_write16(u16 reg, u16 val)
|
||||||
*(vu16*)(SDMMC_BASE + reg) = val;
|
{
|
||||||
|
*(vu16 *)(SDMMC_BASE + reg) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 sdmmc_read32(u16 reg) {
|
static inline u32 sdmmc_read32(u16 reg)
|
||||||
return *(vu32*)(SDMMC_BASE + reg);
|
{
|
||||||
|
return *(vu32 *)(SDMMC_BASE + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_write32(u16 reg, u32 val) {
|
static inline void sdmmc_write32(u16 reg, u32 val)
|
||||||
*(vu32*)(SDMMC_BASE + reg) = val;
|
{
|
||||||
|
*(vu32 *)(SDMMC_BASE + reg) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
|
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set)
|
||||||
|
{
|
||||||
u16 val = sdmmc_read16(reg);
|
u16 val = sdmmc_read16(reg);
|
||||||
val &= ~clear;
|
val &= ~clear;
|
||||||
val |= set;
|
val |= set;
|
||||||
@@ -38,172 +63,215 @@ static inline void setckl(u32 data)
|
|||||||
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mmcdevice *getMMCDevice(int drive)
|
mmcdevice *getMMCDevice(int drive)
|
||||||
{
|
{
|
||||||
if(drive==0) return &handleNAND;
|
if(drive == 0) return &handleNAND;
|
||||||
return &handleSD;
|
return &handleSD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx)
|
static int geterror(struct mmcdevice *ctx)
|
||||||
{
|
{
|
||||||
return (ctx->error << 29) >> 31;
|
return (int)((ctx->error << 29) >> 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
|
static void inittarget(struct mmcdevice *ctx)
|
||||||
{
|
{
|
||||||
sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
|
sdmmc_mask16(REG_SDPORTSEL, 0x3, (u16)ctx->devicenumber);
|
||||||
setckl(ctx->clk);
|
setckl(ctx->clk);
|
||||||
if (ctx->SDOPT == 0) {
|
if(ctx->SDOPT == 0) sdmmc_mask16(REG_SDOPT, 0, 0x8000);
|
||||||
sdmmc_mask16(REG_SDOPT, 0, 0x8000);
|
else sdmmc_mask16(REG_SDOPT, 0x8000, 0);
|
||||||
} else {
|
|
||||||
sdmmc_mask16(REG_SDOPT, 0x8000, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
|
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
|
||||||
{
|
{
|
||||||
bool getSDRESP = (cmd << 15) >> 31;
|
u32 getSDRESP = (cmd << 15) >> 31;
|
||||||
u16 flags = (cmd << 15) >> 31;
|
u16 flags = (cmd << 15) >> 31;
|
||||||
const bool readdata = cmd & 0x20000;
|
const int readdata = cmd & 0x20000;
|
||||||
const bool writedata = cmd & 0x40000;
|
const int writedata = cmd & 0x40000;
|
||||||
|
|
||||||
if (readdata || writedata)
|
if(readdata || writedata)
|
||||||
flags |= TMIO_STAT0_DATAEND;
|
flags |= TMIO_STAT0_DATAEND;
|
||||||
|
|
||||||
ctx->error = 0;
|
ctx->error = 0;
|
||||||
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
|
while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working?
|
||||||
sdmmc_write16(REG_SDIRMASK0,0);
|
sdmmc_write16(REG_SDIRMASK0, 0);
|
||||||
sdmmc_write16(REG_SDIRMASK1,0);
|
sdmmc_write16(REG_SDIRMASK1, 0);
|
||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
sdmmc_write16(REG_SDSTATUS0, 0);
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
sdmmc_write16(REG_SDSTATUS1, 0);
|
||||||
sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
|
sdmmc_mask16(REG_DATACTL32, 0x1800, 0);
|
||||||
|
sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF);
|
||||||
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
|
sdmmc_write16(REG_SDCMDARG1, args >> 16);
|
||||||
sdmmc_write16(REG_SDCMDARG1,args >> 16);
|
sdmmc_write16(REG_SDCMD, cmd & 0xFFFF);
|
||||||
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
|
|
||||||
|
|
||||||
u32 size = ctx->size;
|
u32 size = ctx->size;
|
||||||
vu8 *dataPtr = ctx->data;
|
u8 *rDataPtr = ctx->rData;
|
||||||
|
const u8 *tDataPtr = ctx->tData;
|
||||||
|
|
||||||
bool useBuf = ( NULL != dataPtr );
|
bool rUseBuf = rDataPtr != NULL;
|
||||||
|
bool tUseBuf = tDataPtr != NULL;
|
||||||
|
|
||||||
u16 status0 = 0;
|
u16 status0 = 0;
|
||||||
while(true) {
|
while(true)
|
||||||
u16 status1 = sdmmc_read16(REG_SDSTATUS1);
|
{
|
||||||
if (status1 & TMIO_STAT1_RXRDY) {
|
vu16 status1 = sdmmc_read16(REG_SDSTATUS1);
|
||||||
if (readdata && useBuf) {
|
vu16 ctl32 = sdmmc_read16(REG_DATACTL32);
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
if((ctl32 & 0x100))
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
|
{
|
||||||
if (size > 0x1FF) {
|
if(readdata)
|
||||||
for(int i = 0; i<0x200; i+=2) {
|
{
|
||||||
u16 data = sdmmc_read16(REG_SDFIFO);
|
if(rUseBuf)
|
||||||
*dataPtr++ = data & 0xFF;
|
{
|
||||||
*dataPtr++ = data >> 8;
|
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
||||||
|
if(size > 0x1FF)
|
||||||
|
{
|
||||||
|
//Gabriel Marcano: This implementation doesn't assume alignment.
|
||||||
|
//I've removed the alignment check doen with former rUseBuf32 as a result
|
||||||
|
for(int i = 0; i < 0x200; i += 4)
|
||||||
|
{
|
||||||
|
u32 data = sdmmc_read32(REG_SDFIFO32);
|
||||||
|
*rDataPtr++ = data;
|
||||||
|
*rDataPtr++ = data >> 8;
|
||||||
|
*rDataPtr++ = data >> 16;
|
||||||
|
*rDataPtr++ = data >> 24;
|
||||||
|
}
|
||||||
|
size -= 0x200;
|
||||||
}
|
}
|
||||||
size -= 0x200;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status1 & TMIO_STAT1_TXRQ) {
|
sdmmc_mask16(REG_DATACTL32, 0x800, 0);
|
||||||
if (writedata && useBuf) {
|
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
|
|
||||||
if (size > 0x1FF) {
|
|
||||||
for (int i = 0; i<0x200; i+=2) {
|
|
||||||
u16 data = *dataPtr++;
|
|
||||||
data |= *dataPtr++ << 8;
|
|
||||||
sdmmc_write16(REG_SDFIFO, data);
|
|
||||||
}
|
|
||||||
size -= 0x200;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status1 & TMIO_MASK_GW) {
|
if(!(ctl32 & 0x200))
|
||||||
|
{
|
||||||
|
if(writedata)
|
||||||
|
{
|
||||||
|
if(tUseBuf)
|
||||||
|
{
|
||||||
|
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
||||||
|
if(size > 0x1FF)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 0x200; i += 4)
|
||||||
|
{
|
||||||
|
u32 data = *tDataPtr++;
|
||||||
|
data |= (u32)*tDataPtr++ << 8;
|
||||||
|
data |= (u32)*tDataPtr++ << 16;
|
||||||
|
data |= (u32)*tDataPtr++ << 24;
|
||||||
|
sdmmc_write32(REG_SDFIFO32, data);
|
||||||
|
}
|
||||||
|
size -= 0x200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(status1 & TMIO_MASK_GW)
|
||||||
|
{
|
||||||
ctx->error |= 4;
|
ctx->error |= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
|
if(!(status1 & TMIO_STAT1_CMD_BUSY))
|
||||||
|
{
|
||||||
status0 = sdmmc_read16(REG_SDSTATUS0);
|
status0 = sdmmc_read16(REG_SDSTATUS0);
|
||||||
if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
||||||
|
{
|
||||||
ctx->error |= 0x1;
|
ctx->error |= 0x1;
|
||||||
if (status0 & TMIO_STAT0_DATAEND)
|
}
|
||||||
|
if(status0 & TMIO_STAT0_DATAEND)
|
||||||
|
{
|
||||||
ctx->error |= 0x2;
|
ctx->error |= 0x2;
|
||||||
|
}
|
||||||
|
|
||||||
if ((status0 & flags) == flags)
|
if((status0 & flags) == flags)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
|
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
|
||||||
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
|
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
|
||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
sdmmc_write16(REG_SDSTATUS0, 0);
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
sdmmc_write16(REG_SDSTATUS1, 0);
|
||||||
|
|
||||||
if (getSDRESP != 0) {
|
if(getSDRESP != 0)
|
||||||
ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16);
|
{
|
||||||
ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16);
|
ctx->ret[0] = (u32)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16));
|
||||||
ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16);
|
ctx->ret[1] = (u32)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16));
|
||||||
ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16);
|
ctx->ret[2] = (u32)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16));
|
||||||
|
ctx->ret[3] = (u32)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in)
|
int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in)
|
||||||
{
|
{
|
||||||
if (handleSD.isSDHC == 0)
|
if(handleSD.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
|
||||||
inittarget(&handleSD);
|
inittarget(&handleSD);
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP, 0x100);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
sdmmc_write16(REG_SDBLKLEN32, 0x200);
|
||||||
handleSD.data = in;
|
sdmmc_write16(REG_SDBLKCOUNT, numsectors);
|
||||||
|
handleSD.tData = in;
|
||||||
handleSD.size = numsectors << 9;
|
handleSD.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleSD,0x52C19,sector_no);
|
sdmmc_send_command(&handleSD, 0x52C19, sector_no);
|
||||||
return geterror(&handleSD);
|
return geterror(&handleSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
|
int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
||||||
{
|
{
|
||||||
if (handleSD.isSDHC == 0)
|
if(handleSD.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
|
||||||
inittarget(&handleSD);
|
inittarget(&handleSD);
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP, 0x100);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
sdmmc_write16(REG_SDBLKLEN32, 0x200);
|
||||||
handleSD.data = out;
|
sdmmc_write16(REG_SDBLKCOUNT, numsectors);
|
||||||
|
handleSD.rData = out;
|
||||||
handleSD.size = numsectors << 9;
|
handleSD.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleSD,0x33C12,sector_no);
|
sdmmc_send_command(&handleSD, 0x33C12, sector_no);
|
||||||
return geterror(&handleSD);
|
return geterror(&handleSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
|
int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
||||||
{
|
{
|
||||||
if (handleNAND.isSDHC == 0)
|
if(handleNAND.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
|
||||||
inittarget(&handleNAND);
|
inittarget(&handleNAND);
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP, 0x100);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
sdmmc_write16(REG_SDBLKLEN32, 0x200);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT, numsectors);
|
||||||
handleNAND.data = out;
|
handleNAND.rData = out;
|
||||||
handleNAND.size = numsectors << 9;
|
handleNAND.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleNAND,0x33C12,sector_no);
|
sdmmc_send_command(&handleNAND, 0x33C12, sector_no);
|
||||||
inittarget(&handleSD);
|
inittarget(&handleSD);
|
||||||
return geterror(&handleNAND);
|
return geterror(&handleNAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 calcSDSize(u8* csd, int type)
|
/*
|
||||||
|
int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental
|
||||||
|
{
|
||||||
|
if(handleNAND.isSDHC == 0) sector_no <<= 9;
|
||||||
|
inittarget(&handleNAND);
|
||||||
|
sdmmc_write16(REG_SDSTOP, 0x100);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
|
||||||
|
sdmmc_write16(REG_SDBLKLEN32, 0x200);
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT, numsectors);
|
||||||
|
handleNAND.tData = in;
|
||||||
|
handleNAND.size = numsectors << 9;
|
||||||
|
sdmmc_send_command(&handleNAND, 0x52C19, sector_no);
|
||||||
|
inittarget(&handleSD);
|
||||||
|
return geterror(&handleNAND);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u32 calcSDSize(u8 *csd, int type)
|
||||||
{
|
{
|
||||||
u32 result = 0;
|
u32 result = 0;
|
||||||
if (type == -1) type = csd[14] >> 6;
|
if(type == -1) type = csd[14] >> 6;
|
||||||
switch (type) {
|
switch(type)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
u32 block_len = csd[9] & 0xf;
|
u32 block_len = csd[9] & 0xF;
|
||||||
block_len = 1u << block_len;
|
block_len = 1u << block_len;
|
||||||
u32 mult = (u32)(csd[4] >> 7) | (u32)((csd[5] & 3) << 1);
|
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
|
||||||
mult = 1u << (mult + 2);
|
mult = 1u << (mult + 2);
|
||||||
result = csd[8] & 3;
|
result = csd[8] & 3;
|
||||||
result = (result << 8) | csd[7];
|
result = (result << 8) | csd[7];
|
||||||
@@ -212,18 +280,42 @@ static u32 calcSDSize(u8* csd, int type)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
result = csd[7] & 0x3f;
|
result = csd[7] & 0x3F;
|
||||||
result = (result << 8) | csd[6];
|
result = (result << 8) | csd[6];
|
||||||
result = (result << 8) | csd[5];
|
result = (result << 8) | csd[5];
|
||||||
result = (result + 1) * 1024;
|
result = (result + 1) * 1024;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break; //Do nothing otherwise
|
break; //Do nothing otherwise FIXME perhaps return some error?
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitSD()
|
static void InitSD()
|
||||||
|
{
|
||||||
|
*(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
||||||
|
*(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
||||||
|
*(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32
|
||||||
|
*(vu16 *)0x100060D8 = (*(vu16 *)0x100060D8 & 0xFFDD) | 2;
|
||||||
|
*(vu16 *)0x10006100 &= 0xFFFFu; //SDDATACTL32
|
||||||
|
*(vu16 *)0x100060D8 &= 0xFFDFu; //SDDATACTL
|
||||||
|
*(vu16 *)0x10006104 = 512; //SDBLKLEN32
|
||||||
|
*(vu16 *)0x10006108 = 1; //SDBLKCOUNT32
|
||||||
|
*(vu16 *)0x100060E0 &= 0xFFFEu; //SDRESET
|
||||||
|
*(vu16 *)0x100060E0 |= 1u; //SDRESET
|
||||||
|
*(vu16 *)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
||||||
|
*(vu16 *)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
||||||
|
*(vu16 *)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
||||||
|
*(vu16 *)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
||||||
|
*(vu16 *)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
||||||
|
*(vu16 *)0x10006024 = 0x20;
|
||||||
|
*(vu16 *)0x10006028 = 0x40EE;
|
||||||
|
*(vu16 *)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
||||||
|
*(vu16 *)0x10006026 = 512; //SDBLKLEN
|
||||||
|
*(vu16 *)0x10006008 = 0; //SDSTOP
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Nand_Init()
|
||||||
{
|
{
|
||||||
//NAND
|
//NAND
|
||||||
handleNAND.isSDHC = 0;
|
handleNAND.isSDHC = 0;
|
||||||
@@ -233,80 +325,50 @@ static void InitSD()
|
|||||||
handleNAND.clk = 0x80;
|
handleNAND.clk = 0x80;
|
||||||
handleNAND.devicenumber = 1;
|
handleNAND.devicenumber = 1;
|
||||||
|
|
||||||
//SD
|
|
||||||
handleSD.isSDHC = 0;
|
|
||||||
handleSD.SDOPT = 0;
|
|
||||||
handleSD.res = 0;
|
|
||||||
handleSD.initarg = 0;
|
|
||||||
handleSD.clk = 0x80;
|
|
||||||
handleSD.devicenumber = 0;
|
|
||||||
|
|
||||||
*(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
|
||||||
*(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
|
||||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
|
||||||
*(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
|
|
||||||
*(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
|
|
||||||
*(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
|
|
||||||
*(vu16*)0x10006104 = 0; //SDBLKLEN32
|
|
||||||
*(vu16*)0x10006108 = 1; //SDBLKCOUNT32
|
|
||||||
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
|
|
||||||
*(vu16*)0x100060E0 |= 1u; //SDRESET
|
|
||||||
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
|
||||||
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
|
||||||
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
|
||||||
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
|
||||||
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
|
|
||||||
*(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
|
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
|
||||||
*(vu16*)0x10006026 = 512; //SDBLKLEN
|
|
||||||
*(vu16*)0x10006008 = 0; //SDSTOP
|
|
||||||
|
|
||||||
inittarget(&handleSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int Nand_Init()
|
|
||||||
{
|
|
||||||
inittarget(&handleNAND);
|
inittarget(&handleNAND);
|
||||||
ioDelay(0xF000);
|
waitcycles(0xF000);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0,0);
|
sdmmc_send_command(&handleNAND, 0, 0);
|
||||||
|
|
||||||
do {
|
do
|
||||||
do {
|
{
|
||||||
sdmmc_send_command(&handleNAND,0x10701,0x100000);
|
do
|
||||||
} while ( !(handleNAND.error & 1) );
|
{
|
||||||
} while((handleNAND.ret[0] & 0x80000000) == 0);
|
sdmmc_send_command(&handleNAND, 0x10701, 0x100000);
|
||||||
|
}
|
||||||
|
while(!(handleNAND.error & 1));
|
||||||
|
}
|
||||||
|
while((handleNAND.ret[0] & 0x80000000) == 0);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10602,0x0);
|
sdmmc_send_command(&handleNAND, 0x10602, 0x0);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
|
sdmmc_send_command(&handleNAND, 0x10403, handleNAND.initarg << 0x10);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
|
sdmmc_send_command(&handleNAND, 0x10609, handleNAND.initarg << 0x10);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
|
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0], 0);
|
||||||
handleNAND.clk = 1;
|
handleNAND.clk = 1;
|
||||||
setckl(1);
|
setckl(1);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
|
sdmmc_send_command(&handleNAND, 0x10407, handleNAND.initarg << 0x10);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
handleNAND.SDOPT = 1;
|
handleNAND.SDOPT = 1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
|
sdmmc_send_command(&handleNAND, 0x10506, 0x3B70100);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
|
sdmmc_send_command(&handleNAND, 0x10506, 0x3B90100);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
|
sdmmc_send_command(&handleNAND, 0x1040D, handleNAND.initarg << 0x10);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10410,0x200);
|
sdmmc_send_command(&handleNAND, 0x10410, 0x200);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handleNAND.error & 0x4)) return -1;
|
||||||
|
|
||||||
handleNAND.clk |= 0x200;
|
handleNAND.clk |= 0x200;
|
||||||
|
|
||||||
@@ -317,113 +379,102 @@ static int Nand_Init()
|
|||||||
|
|
||||||
static int SD_Init()
|
static int SD_Init()
|
||||||
{
|
{
|
||||||
|
//SD
|
||||||
|
handleSD.isSDHC = 0;
|
||||||
|
handleSD.SDOPT = 0;
|
||||||
|
handleSD.res = 0;
|
||||||
|
handleSD.initarg = 0;
|
||||||
|
handleSD.clk = 0x80;
|
||||||
|
handleSD.devicenumber = 0;
|
||||||
|
|
||||||
inittarget(&handleSD);
|
inittarget(&handleSD);
|
||||||
|
|
||||||
ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems
|
waitcycles(1u << 22); //Card needs a little bit of time to be detected, it seems FIXME test again to see what a good number is for the delay
|
||||||
|
|
||||||
//If not inserted
|
//If not inserted
|
||||||
if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1;
|
if(!(*((vu16 *)(SDMMC_BASE + REG_SDSTATUS0)) & TMIO_STAT0_SIGSTATE)) return 5;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0,0);
|
sdmmc_send_command(&handleSD, 0, 0);
|
||||||
sdmmc_send_command(&handleSD,0x10408,0x1AA);
|
sdmmc_send_command(&handleSD, 0x10408, 0x1AA);
|
||||||
//u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
|
|
||||||
u32 temp = (handleSD.error & 0x1) << 0x1E;
|
u32 temp = (handleSD.error & 0x1) << 0x1E;
|
||||||
|
|
||||||
//int count = 0;
|
|
||||||
u32 temp2 = 0;
|
u32 temp2 = 0;
|
||||||
do {
|
do
|
||||||
do {
|
{
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
do
|
||||||
sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
{
|
||||||
|
sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10);
|
||||||
|
sdmmc_send_command(&handleSD, 0x10769, 0x00FF8000 | temp);
|
||||||
temp2 = 1;
|
temp2 = 1;
|
||||||
} while ( !(handleSD.error & 1) );
|
}
|
||||||
|
while(!(handleSD.error & 1));
|
||||||
} while((handleSD.ret[0] & 0x80000000) == 0);
|
}
|
||||||
|
while((handleSD.ret[0] & 0x80000000) == 0);
|
||||||
|
|
||||||
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
|
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
|
||||||
temp2 = 0;
|
temp2 = 0;
|
||||||
|
|
||||||
handleSD.isSDHC = temp2;
|
handleSD.isSDHC = temp2;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10602,0);
|
sdmmc_send_command(&handleSD, 0x10602, 0);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10403,0);
|
sdmmc_send_command(&handleSD, 0x10403, 0);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -2;
|
||||||
handleSD.initarg = handleSD.ret[0] >> 0x10;
|
handleSD.initarg = handleSD.ret[0] >> 0x10;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handleSD, 0x10609, handleSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -3;
|
||||||
|
|
||||||
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
|
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0], -1);
|
||||||
handleSD.clk = 1;
|
handleSD.clk = 1;
|
||||||
setckl(1);
|
setckl(1);
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handleSD, 0x10507, handleSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -4;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -5;
|
||||||
|
|
||||||
handleSD.SDOPT = 1;
|
handleSD.SDOPT = 1;
|
||||||
sdmmc_send_command(&handleSD,0x10446,0x2);
|
sdmmc_send_command(&handleSD, 0x10446, 0x2);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -6;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handleSD, 0x1040D, handleSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -7;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10410,0x200);
|
sdmmc_send_command(&handleSD, 0x10410, 0x200);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handleSD.error & 0x4)) return -8;
|
||||||
handleSD.clk |= 0x200;
|
handleSD.clk |= 0x200;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sdmmc_get_cid(bool isNand, u32 *info)
|
||||||
|
{
|
||||||
|
struct mmcdevice *device = isNand ? &handleNAND : &handleSD;
|
||||||
|
|
||||||
|
inittarget(device);
|
||||||
|
|
||||||
|
// use cmd7 to put sd card in standby mode
|
||||||
|
// CMD7
|
||||||
|
sdmmc_send_command(device, 0x10507, 0);
|
||||||
|
|
||||||
|
// get sd card info
|
||||||
|
// use cmd10 to read CID
|
||||||
|
sdmmc_send_command(device, 0x1060A, device->initarg << 0x10);
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
info[i] = device->ret[i];
|
||||||
|
|
||||||
|
// put sd card back to transfer mode
|
||||||
|
// CMD7
|
||||||
|
sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
void sdmmc_sdcard_init()
|
void sdmmc_sdcard_init()
|
||||||
{
|
{
|
||||||
InitSD();
|
InitSD();
|
||||||
Nand_Init();
|
Nand_Init();
|
||||||
SD_Init();
|
SD_Init();
|
||||||
}
|
|
||||||
|
|
||||||
int sdmmc_get_cid(int isNand, uint32_t *info)
|
|
||||||
{
|
|
||||||
struct mmcdevice *device;
|
|
||||||
if(isNand)
|
|
||||||
device = &handleNAND;
|
|
||||||
else
|
|
||||||
device = &handleSD;
|
|
||||||
|
|
||||||
inittarget(device);
|
|
||||||
// use cmd7 to put sd card in standby mode
|
|
||||||
// CMD7
|
|
||||||
{
|
|
||||||
sdmmc_send_command(device,0x10507,0);
|
|
||||||
//if((device->error & 0x4)) return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get sd card info
|
|
||||||
// use cmd10 to read CID
|
|
||||||
{
|
|
||||||
sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
|
|
||||||
//if((device->error & 0x4)) return -2;
|
|
||||||
|
|
||||||
for( int i = 0; i < 4; ++i ) {
|
|
||||||
info[i] = device->ret[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// put sd card back to transfer mode
|
|
||||||
// CMD7
|
|
||||||
{
|
|
||||||
sdmmc_send_command(device,0x10507,device->initarg << 0x10);
|
|
||||||
//if((device->error & 0x4)) return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isNand)
|
|
||||||
{
|
|
||||||
inittarget(&handleSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
@@ -1,52 +1,48 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "../../types.h"
|
||||||
|
|
||||||
#define SDMMC_BASE 0x10006000u
|
#define SDMMC_BASE 0x10006000
|
||||||
|
|
||||||
#define REG_SDCMD 0x00
|
#define REG_SDCMD 0x00
|
||||||
#define REG_SDPORTSEL 0x02
|
#define REG_SDPORTSEL 0x02
|
||||||
#define REG_SDCMDARG 0x04
|
#define REG_SDCMDARG 0x04
|
||||||
#define REG_SDCMDARG0 0x04
|
#define REG_SDCMDARG0 0x04
|
||||||
#define REG_SDCMDARG1 0x06
|
#define REG_SDCMDARG1 0x06
|
||||||
#define REG_SDSTOP 0x08
|
#define REG_SDSTOP 0x08
|
||||||
#define REG_SDBLKCOUNT 0x0a
|
#define REG_SDBLKCOUNT 0x0A
|
||||||
|
|
||||||
#define REG_SDRESP0 0x0c
|
#define REG_SDRESP0 0x0C
|
||||||
#define REG_SDRESP1 0x0e
|
#define REG_SDRESP1 0x0E
|
||||||
#define REG_SDRESP2 0x10
|
#define REG_SDRESP2 0x10
|
||||||
#define REG_SDRESP3 0x12
|
#define REG_SDRESP3 0x12
|
||||||
#define REG_SDRESP4 0x14
|
#define REG_SDRESP4 0x14
|
||||||
#define REG_SDRESP5 0x16
|
#define REG_SDRESP5 0x16
|
||||||
#define REG_SDRESP6 0x18
|
#define REG_SDRESP6 0x18
|
||||||
#define REG_SDRESP7 0x1a
|
#define REG_SDRESP7 0x1A
|
||||||
|
|
||||||
#define REG_SDSTATUS0 0x1c
|
#define REG_SDSTATUS0 0x1C
|
||||||
#define REG_SDSTATUS1 0x1e
|
#define REG_SDSTATUS1 0x1E
|
||||||
|
|
||||||
#define REG_SDIRMASK0 0x20
|
#define REG_SDIRMASK0 0x20
|
||||||
#define REG_SDIRMASK1 0x22
|
#define REG_SDIRMASK1 0x22
|
||||||
#define REG_SDCLKCTL 0x24
|
#define REG_SDCLKCTL 0x24
|
||||||
|
|
||||||
#define REG_SDBLKLEN 0x26
|
#define REG_SDBLKLEN 0x26
|
||||||
#define REG_SDOPT 0x28
|
#define REG_SDOPT 0x28
|
||||||
#define REG_SDFIFO 0x30
|
#define REG_SDFIFO 0x30
|
||||||
|
|
||||||
#define REG_SDDATACTL 0xd8
|
#define REG_DATACTL 0xD8
|
||||||
#define REG_SDRESET 0xe0
|
#define REG_SDRESET 0xE0
|
||||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
#define REG_SDPROTECTED 0xF6 //bit 0 determines if sd is protected or not?
|
||||||
|
|
||||||
#define REG_SDDATACTL32 0x100
|
#define REG_DATACTL32 0x100
|
||||||
#define REG_SDBLKLEN32 0x104
|
#define REG_SDBLKLEN32 0x104
|
||||||
#define REG_SDBLKCOUNT32 0x108
|
#define REG_SDBLKCOUNT32 0x108
|
||||||
#define REG_SDFIFO32 0x10C
|
#define REG_SDFIFO32 0x10C
|
||||||
|
|
||||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||||
#define REG_RESET_SDIO 0x1e0
|
#define REG_RESET_SDIO 0x1E0
|
||||||
|
|
||||||
#define TMIO_STAT0_CMDRESPEND 0x0001
|
#define TMIO_STAT0_CMDRESPEND 0x0001
|
||||||
#define TMIO_STAT0_DATAEND 0x0004
|
#define TMIO_STAT0_DATAEND 0x0004
|
||||||
@@ -70,31 +66,7 @@
|
|||||||
#define TMIO_STAT1_CMD_BUSY 0x4000
|
#define TMIO_STAT1_CMD_BUSY 0x4000
|
||||||
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
||||||
|
|
||||||
//Comes from TWLSDK mongoose.tef DWARF info
|
#define TMIO_MASK_ALL 0x837F031D
|
||||||
#define SDMC_NORMAL 0x00000000
|
|
||||||
#define SDMC_ERR_COMMAND 0x00000001
|
|
||||||
#define SDMC_ERR_CRC 0x00000002
|
|
||||||
#define SDMC_ERR_END 0x00000004
|
|
||||||
#define SDMC_ERR_TIMEOUT 0x00000008
|
|
||||||
#define SDMC_ERR_FIFO_OVF 0x00000010
|
|
||||||
#define SDMC_ERR_FIFO_UDF 0x00000020
|
|
||||||
#define SDMC_ERR_WP 0x00000040
|
|
||||||
#define SDMC_ERR_ABORT 0x00000080
|
|
||||||
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
|
|
||||||
#define SDMC_ERR_PARAM 0x00000200
|
|
||||||
#define SDMC_ERR_R1_STATUS 0x00000800
|
|
||||||
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
|
|
||||||
#define SDMC_ERR_RESET 0x00002000
|
|
||||||
#define SDMC_ERR_ILA 0x00004000
|
|
||||||
#define SDMC_ERR_INFO_DETECT 0x00008000
|
|
||||||
|
|
||||||
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
|
|
||||||
#define SDMC_STAT_ERR_CC 0x00100000
|
|
||||||
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
|
|
||||||
#define SDMC_STAT_ERR_CRC 0x00800000
|
|
||||||
#define SDMC_STAT_ERR_OTHER 0xf9c70008
|
|
||||||
|
|
||||||
#define TMIO_MASK_ALL 0x837f031d
|
|
||||||
|
|
||||||
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
||||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||||
@@ -103,7 +75,8 @@
|
|||||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||||
|
|
||||||
typedef struct mmcdevice {
|
typedef struct mmcdevice {
|
||||||
vu8* data;
|
u8 *rData;
|
||||||
|
const u8 *tData;
|
||||||
u32 size;
|
u32 size;
|
||||||
u32 error;
|
u32 error;
|
||||||
u16 stat0;
|
u16 stat0;
|
||||||
@@ -118,12 +91,10 @@ typedef struct mmcdevice {
|
|||||||
u32 res;
|
u32 res;
|
||||||
} mmcdevice;
|
} mmcdevice;
|
||||||
|
|
||||||
mmcdevice *getMMCDevice(int drive);
|
|
||||||
|
|
||||||
void sdmmc_sdcard_init();
|
void sdmmc_sdcard_init();
|
||||||
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||||
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
||||||
|
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||||
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
//int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
||||||
|
void sdmmc_get_cid(bool isNand, u32 *info);
|
||||||
int sdmmc_get_cid( int isNand, uint32_t *info);
|
mmcdevice *getMMCDevice(int drive);
|
||||||
742
source/firm.c
742
source/firm.c
@@ -1,5 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* firm.c
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
@@ -8,395 +26,565 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "cache.h"
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "screen.h"
|
||||||
#include "loader.h"
|
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "../build/patches.h"
|
#include "pin.h"
|
||||||
|
#include "../build/injector.h"
|
||||||
|
|
||||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
#ifdef DEV
|
||||||
|
#include "exceptions.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern u16 launchedFirmTidLow[8]; //Defined in start.s
|
||||||
|
|
||||||
|
static firmHeader *firm = (firmHeader *)0x24000000;
|
||||||
static const firmSectionHeader *section;
|
static const firmSectionHeader *section;
|
||||||
|
|
||||||
u32 config,
|
u32 emuOffset;
|
||||||
console,
|
bool isN3DS,
|
||||||
firmSource,
|
isDevUnit,
|
||||||
emuOffset;
|
isFirmlaunch;
|
||||||
|
CfgData configData;
|
||||||
|
FirmwareSource firmSource;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
u32 bootType,
|
bool isA9lh;
|
||||||
firmType,
|
u32 configTemp,
|
||||||
nandType,
|
|
||||||
a9lhInstalled,
|
|
||||||
updatedSys,
|
|
||||||
needConfig,
|
|
||||||
newConfig,
|
|
||||||
emuHeader;
|
emuHeader;
|
||||||
|
FirmwareType firmType;
|
||||||
|
FirmwareSource nandType;
|
||||||
|
ConfigurationStatus needConfig;
|
||||||
|
|
||||||
//Detect the console being used
|
//Detect the console being used
|
||||||
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
isN3DS = PDN_MPCORE_CFG == 7;
|
||||||
|
|
||||||
|
//Detect dev units
|
||||||
|
isDevUnit = CFG_UNITINFO != 0;
|
||||||
|
|
||||||
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
||||||
mountFs();
|
mountFs();
|
||||||
|
|
||||||
//Attempt to read the configuration file
|
//Attempt to read the configuration file
|
||||||
const char configPath[] = "/luma/config.bin";
|
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
||||||
if(fileRead(&config, configPath, 4)) needConfig = 1;
|
|
||||||
else
|
#ifdef DEV
|
||||||
{
|
detectAndProcessExceptionDumps();
|
||||||
config = 0;
|
#endif
|
||||||
needConfig = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Determine if this is a firmlaunch boot
|
//Determine if this is a firmlaunch boot
|
||||||
if(*(vu8 *)0x23F00005)
|
if(launchedFirmTidLow[5] != 0)
|
||||||
{
|
{
|
||||||
if(needConfig == 2) mcuReboot();
|
isFirmlaunch = true;
|
||||||
|
|
||||||
bootType = 1;
|
if(needConfig == CREATE_CONFIGURATION) mcuReboot();
|
||||||
|
|
||||||
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
||||||
firmType = *(vu8 *)0x23F00005 - '0';
|
firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0');
|
||||||
|
|
||||||
nandType = BOOTCONFIG(0, 3);
|
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||||
firmSource = BOOTCONFIG(2, 1);
|
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||||
a9lhInstalled = BOOTCONFIG(3, 1);
|
isA9lh = BOOTCFG_A9LH != 0;
|
||||||
updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0;
|
|
||||||
|
#ifdef DEV
|
||||||
|
if(isA9lh) installArm9Handlers();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bootType = 0;
|
isFirmlaunch = false;
|
||||||
firmType = 0;
|
firmType = NATIVE_FIRM;
|
||||||
|
|
||||||
//Determine if booting with A9LH
|
//Determine if booting with A9LH
|
||||||
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
|
isA9lh = !PDN_SPI_CNT;
|
||||||
|
|
||||||
//Retrieve the last booted FIRM
|
#ifdef DEV
|
||||||
u32 previousFirm = CFG_BOOTENV;
|
if(isA9lh) installArm9Handlers();
|
||||||
|
#endif
|
||||||
|
|
||||||
//Get pressed buttons
|
//Get pressed buttons
|
||||||
u32 pressed = HID_PAD;
|
u32 pressed = HID_PAD;
|
||||||
|
|
||||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
//Save old options and begin saving the new boot configuration
|
||||||
if(a9lhBoot || CONFIG(2))
|
configTemp = (configData.config & 0xFFFFFE00) | ((u32)isA9lh << 6);
|
||||||
{
|
|
||||||
if(pressed == SAFE_MODE)
|
|
||||||
error("Using Safe Mode would brick you, or remove A9LH!");
|
|
||||||
|
|
||||||
a9lhInstalled = 1;
|
//If it's a MCU reboot, try to force boot options
|
||||||
|
if(isA9lh && CFG_BOOTENV)
|
||||||
//Check setting for > 9.2 sysNAND
|
|
||||||
updatedSys = CONFIG(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a9lhInstalled = 0;
|
|
||||||
updatedSys = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
newConfig = a9lhInstalled << 3;
|
|
||||||
|
|
||||||
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
|
||||||
try to force boot options */
|
|
||||||
if(a9lhBoot && previousFirm && needConfig == 1)
|
|
||||||
{
|
{
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
if(previousFirm == 7)
|
if(CFG_BOOTENV == 7)
|
||||||
{
|
{
|
||||||
nandType = 0;
|
nandType = FIRMWARE_SYSNAND;
|
||||||
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
|
firmSource = CONFIG(USESYSFIRM) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
|
||||||
needConfig = 0;
|
needConfig = DONT_CONFIGURE;
|
||||||
|
|
||||||
//Flag to prevent multiple boot options-forcing
|
//Flag to prevent multiple boot options-forcing
|
||||||
newConfig |= 1 << 4;
|
configTemp |= 1 << 7;
|
||||||
}
|
}
|
||||||
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
|
|
||||||
|
/* Else, force the last used boot options unless a button is pressed
|
||||||
or the no-forcing flag is set */
|
or the no-forcing flag is set */
|
||||||
else if(!(pressed & OVERRIDE_BUTTONS) && !BOOTCONFIG(4, 1))
|
else if(needConfig != CREATE_CONFIGURATION && !pressed && !BOOTCFG_NOFORCEFLAG)
|
||||||
{
|
{
|
||||||
nandType = BOOTCONFIG(0, 3);
|
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||||
firmSource = BOOTCONFIG(2, 1);
|
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||||
needConfig = 0;
|
needConfig = DONT_CONFIGURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Boot options aren't being forced
|
//Boot options aren't being forced
|
||||||
if(needConfig)
|
if(needConfig != DONT_CONFIGURE)
|
||||||
{
|
{
|
||||||
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH,
|
bool pinExists = MULTICONFIG(PIN) != 0 && verifyPin();
|
||||||
the Safe Mode combo is not pressed, chainload an external payload */
|
|
||||||
if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
|
|
||||||
&& pressed != SAFE_MODE)
|
|
||||||
loadPayload();
|
|
||||||
|
|
||||||
//If no configuration file exists or SELECT is held, load configuration menu
|
//If no configuration file exists or SELECT is held, load configuration menu
|
||||||
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
||||||
configureCFW(configPath);
|
|
||||||
|
|
||||||
//If screens are inited or the corresponding option is set, load splash screen
|
if(shouldLoadConfigMenu)
|
||||||
if(PDN_GPU_CNT != 1 || CONFIG(8)) loadSplash();
|
{
|
||||||
|
configMenu(pinExists);
|
||||||
|
|
||||||
//Determine if we need to autoboot sysNAND
|
//Update pressed buttons
|
||||||
u32 autoBootSys = CONFIG(0);
|
pressed = HID_PAD;
|
||||||
|
}
|
||||||
|
|
||||||
//Determine if we need to boot an emuNAND or sysNAND
|
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||||
nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
|
{
|
||||||
|
nandType = FIRMWARE_SYSNAND;
|
||||||
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
|
|
||||||
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
//Flag to tell loader to init SD
|
||||||
or vice-versa, boot the second emuNAND */
|
configTemp |= 1 << 8;
|
||||||
if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3))) nandType++;
|
|
||||||
|
|
||||||
//Determine the NAND we should take the FIRM from
|
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
|
||||||
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
|
if(pinExists && !shouldLoadConfigMenu)
|
||||||
|
{
|
||||||
|
while(HID_PAD & PIN_BUTTONS);
|
||||||
|
chrono(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(CONFIG(PAYLOADSPLASH) && loadSplash()) pressed = HID_PAD;
|
||||||
|
|
||||||
|
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||||
|
chainload an external payload */
|
||||||
|
bool shouldLoadPayload = ((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1))) ||
|
||||||
|
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1));
|
||||||
|
|
||||||
|
if(shouldLoadPayload) loadPayload(pressed);
|
||||||
|
|
||||||
|
if(!CONFIG(PAYLOADSPLASH)) loadSplash();
|
||||||
|
|
||||||
|
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
|
||||||
|
bool useSysAsDefault = isA9lh ? CONFIG(USESYSFIRM) : false;
|
||||||
|
|
||||||
|
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||||
|
if(pressed & BUTTON_R1)
|
||||||
|
{
|
||||||
|
nandType = useSysAsDefault ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
|
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||||
|
with their own FIRM */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nandType = (CONFIG(AUTOBOOTSYS) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
|
||||||
|
firmSource = nandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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 temp;
|
||||||
|
switch(pressed & EMUNAND_BUTTONS)
|
||||||
|
{
|
||||||
|
case BUTTON_UP:
|
||||||
|
temp = FIRMWARE_EMUNAND;
|
||||||
|
break;
|
||||||
|
case BUTTON_RIGHT:
|
||||||
|
temp = FIRMWARE_EMUNAND2;
|
||||||
|
break;
|
||||||
|
case BUTTON_DOWN:
|
||||||
|
temp = FIRMWARE_EMUNAND3;
|
||||||
|
break;
|
||||||
|
case BUTTON_LEFT:
|
||||||
|
temp = FIRMWARE_EMUNAND4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
temp = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nandType == FIRMWARE_EMUNAND) nandType = temp;
|
||||||
|
else firmSource = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we need to boot emuNAND, make sure it exists
|
//If we need to boot EmuNAND, make sure it exists
|
||||||
if(nandType)
|
if(nandType != FIRMWARE_SYSNAND)
|
||||||
{
|
{
|
||||||
getEmunandSect(&emuOffset, &emuHeader, &nandType);
|
locateEmuNand(&emuHeader, &nandType);
|
||||||
if(!nandType) firmSource = 0;
|
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Same if we're using emuNAND as the FIRM source
|
//Same if we're using EmuNAND as the FIRM source
|
||||||
else if(firmSource)
|
else if(firmSource != FIRMWARE_SYSNAND)
|
||||||
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
|
locateEmuNand(&emuHeader, &firmSource);
|
||||||
|
|
||||||
if(!bootType)
|
if(!isFirmlaunch)
|
||||||
{
|
{
|
||||||
newConfig |= nandType | (firmSource << 2);
|
configTemp |= (u32)nandType | ((u32)firmSource << 3);
|
||||||
|
writeConfig(needConfig, configTemp);
|
||||||
/* If the boot configuration is different from previously, overwrite it.
|
|
||||||
Just the no-forcing flag being set is not enough */
|
|
||||||
if((newConfig & 0x2F) != (config & 0x3F))
|
|
||||||
{
|
|
||||||
//Preserve user settings (last 26 bits)
|
|
||||||
newConfig |= config & 0xFFFFFFC0;
|
|
||||||
|
|
||||||
fileWrite(&newConfig, configPath, 4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFirm(firmType, !firmType && updatedSys == !firmSource);
|
u32 firmVersion = loadFirm(&firmType, firmSource);
|
||||||
|
|
||||||
if(!firmType) patchNativeFirm(nandType, emuHeader, a9lhInstalled);
|
switch(firmType)
|
||||||
else patchTwlAgbFirm(firmType);
|
{
|
||||||
|
case NATIVE_FIRM:
|
||||||
|
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
|
||||||
|
break;
|
||||||
|
case SAFE_FIRM:
|
||||||
|
case NATIVE_FIRM1X2X:
|
||||||
|
if(isA9lh) patch1x2xNativeAndSafeFirm();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//Skip patching on unsupported O3DS AGB/TWL FIRMs
|
||||||
|
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
launchFirm(bootType);
|
launchFirm(firmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load FIRM into FCRAM
|
#ifdef DEV
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
||||||
{
|
{
|
||||||
section = firm->section;
|
section = firm->section;
|
||||||
|
|
||||||
/* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM
|
const char *firmwareFiles[4] = {
|
||||||
doesn't match the console, load it from CTRNAND */
|
"/luma/firmware.bin",
|
||||||
if(!externalFirm || !fileRead(firm, "/luma/firmware.bin", 0) ||
|
"/luma/firmware_twl.bin",
|
||||||
(((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
|
"/luma/firmware_agb.bin",
|
||||||
|
"/luma/firmware_safe.bin"
|
||||||
|
};
|
||||||
|
|
||||||
|
//Load FIRM from CTRNAND
|
||||||
|
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||||
|
|
||||||
|
bool loadFromSd = false;
|
||||||
|
|
||||||
|
if(!isN3DS && *firmType == NATIVE_FIRM)
|
||||||
{
|
{
|
||||||
const char *firmFolders[3][2] = {{ "00000002", "20000002" },
|
if(firmVersion < 0x18)
|
||||||
{ "00000102", "20000102" },
|
{
|
||||||
{ "00000202", "20000202" }};
|
//We can't boot < 3.x EmuNANDs
|
||||||
|
if(firmSource != FIRMWARE_SYSNAND)
|
||||||
|
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it");
|
||||||
|
|
||||||
firmRead(firm, firmFolders[firmType][console]);
|
if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM");
|
||||||
decryptExeFs((u8 *)firm);
|
|
||||||
|
*firmType = NATIVE_FIRM1X2X;
|
||||||
|
}
|
||||||
|
|
||||||
|
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD
|
||||||
|
else if(firmVersion < 0x25) loadFromSd = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhInstalled)
|
//Check that the SD FIRM is right for the console from the ARM9 section address
|
||||||
{
|
if(fileRead(firm, *firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)*firmType], 0x400000) &&
|
||||||
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
((section[3].offset ? section[3].address : section[2].address) == (isN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800)))
|
||||||
|
firmVersion = 0xFFFFFFFF;
|
||||||
u32 nativeFirmType;
|
|
||||||
|
|
||||||
if(console)
|
|
||||||
{
|
|
||||||
//Determine if we're booting the 9.0 FIRM
|
|
||||||
nativeFirmType = (arm9Section[0x51] == 0xFF) ? 0 : 1;
|
|
||||||
|
|
||||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
|
||||||
arm9Loader(arm9Section, nativeFirmType);
|
|
||||||
firm->arm9Entry = (u8 *)0x801B01C;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Determine if we're booting the 9.0 FIRM
|
if(loadFromSd) error("An old unsupported FIRM has been detected.\nCopy a valid firmware.bin in /luma to boot");
|
||||||
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
|
decryptExeFs((u8 *)firm);
|
||||||
nativeFirmType = (memcmp(section[2].hash, firm90Hash, 0x10) == 0) ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nativeFirmType || nandType)
|
return firmVersion;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource)
|
||||||
|
{
|
||||||
|
section = firm->section;
|
||||||
|
|
||||||
|
//Load FIRM from CTRNAND
|
||||||
|
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||||
|
|
||||||
|
if(!isN3DS && *firmType == NATIVE_FIRM)
|
||||||
{
|
{
|
||||||
//Find the Process9 NCCH location
|
if(firmVersion < 0x18)
|
||||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
{
|
||||||
|
//We can't boot < 3.x EmuNANDs
|
||||||
|
if(firmSource != FIRMWARE_SYSNAND)
|
||||||
|
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it");
|
||||||
|
|
||||||
//Apply emuNAND patches
|
if(BOOTCFG_SAFEMODE != 0) error("SAFE_MODE is not supported on 1.x/2.x FIRM");
|
||||||
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
|
|
||||||
|
|
||||||
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
*firmType = NATIVE_FIRM1X2X;
|
||||||
if(nativeFirmType) patchReboots(arm9Section, proc9Offset);
|
}
|
||||||
|
|
||||||
|
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD
|
||||||
|
else if(firmVersion < 0x25)
|
||||||
|
{
|
||||||
|
if(!fileRead(firm, "/luma/firmware.bin", 0x400000) || section[2].address != (u8 *)0x8006800)
|
||||||
|
error("An old unsupported FIRM has been detected.\nCopy a valid firmware.bin in /luma to boot");
|
||||||
|
|
||||||
|
firmVersion = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(firmVersion != 0xFFFFFFFF) decryptExeFs((u8 *)firm);
|
||||||
|
|
||||||
|
return firmVersion;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
|
||||||
|
{
|
||||||
|
u8 *arm9Section = (u8 *)firm + section[2].offset,
|
||||||
|
*arm11Section1 = (u8 *)firm + section[1].offset;
|
||||||
|
|
||||||
|
if(isN3DS)
|
||||||
|
{
|
||||||
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
|
arm9Loader(arm9Section);
|
||||||
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
|
||||||
|
else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
|
||||||
|
|
||||||
|
//Find the Process9 .code location, size and memory address
|
||||||
|
u32 process9Size,
|
||||||
|
process9MemAddr;
|
||||||
|
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
//Find Kernel11 SVC table and handler, exceptions page and free space locations
|
||||||
|
u32 baseK11VA;
|
||||||
|
u8 *freeK11Space;
|
||||||
|
u32 *arm11SvcHandler,
|
||||||
|
*arm11ExceptionsPage,
|
||||||
|
*arm11SvcTable = getKernel11Info(arm11Section1, section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage);
|
||||||
|
#else
|
||||||
|
//Find Kernel11 SVC table and free space locations
|
||||||
|
u32 baseK11VA;
|
||||||
|
u8 *freeK11Space;
|
||||||
|
u32 *arm11SvcTable = getKernel11Info(arm11Section1, section[1].size, &baseK11VA, &freeK11Space);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Apply signature patches
|
||||||
|
patchSignatureChecks(process9Offset, process9Size);
|
||||||
|
|
||||||
|
//Apply EmuNAND patches
|
||||||
|
if(nandType != FIRMWARE_SYSNAND)
|
||||||
|
{
|
||||||
|
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
|
||||||
|
patchEmuNand(arm9Section, section[2].size, process9Offset, process9Size, emuHeader, branchAdditive);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||||
if(a9lhInstalled && !nandType)
|
else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
|
||||||
|
|
||||||
|
//Apply firmlaunch patches
|
||||||
|
patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||||
|
|
||||||
|
//11.0 FIRM patches
|
||||||
|
if(firmVersion >= (isN3DS ? 0x21 : 0x52))
|
||||||
{
|
{
|
||||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
//Apply anti-anti-DG patches
|
||||||
*writeOffset = writeBlock[0];
|
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
||||||
*(writeOffset + 1) = writeBlock[1];
|
|
||||||
|
//Restore svcBackdoor
|
||||||
|
reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Apply signature checks patches
|
implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space);
|
||||||
u32 sigOffset,
|
|
||||||
sigOffset2;
|
|
||||||
|
|
||||||
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
|
#ifdef DEV
|
||||||
*(u16 *)sigOffset = sigPatch[0];
|
//Apply UNITINFO patch
|
||||||
*(u16 *)sigOffset2 = sigPatch[0];
|
if(MULTICONFIG(DEVOPTIONS) == 1) patchUnitInfoValueSet(arm9Section, section[2].size);
|
||||||
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
|
||||||
|
|
||||||
if(CONFIG(5))
|
if(isA9lh && MULTICONFIG(DEVOPTIONS) != 2)
|
||||||
{
|
{
|
||||||
//Apply UNITINFO patch
|
//Install ARM11 exception handlers
|
||||||
u8 *unitInfoOffset = getUnitInfoValueSet(arm9Section, section[2].size);
|
u32 codeSetOffset;
|
||||||
*unitInfoOffset = unitInfoPatch;
|
u32 stackAddress = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &codeSetOffset);
|
||||||
|
installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset);
|
||||||
|
|
||||||
|
//Kernel9/Process9 debugging
|
||||||
|
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
|
||||||
|
patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address);
|
||||||
|
patchKernel9Panic(arm9Section, section[2].size);
|
||||||
|
|
||||||
|
//Stub svcBreak11 with "bkpt 65535"
|
||||||
|
patchSvcBreak11(arm11Section1, arm11SvcTable);
|
||||||
|
|
||||||
|
//Stub kernel11Panic with "bkpt 65534"
|
||||||
|
patchKernel11Panic(arm11Section1, section[1].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Replace the FIRM loader with the injector
|
if(CONFIG(PATCHACCESS))
|
||||||
injectLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
|
|
||||||
{
|
|
||||||
//Copy emuNAND code
|
|
||||||
void *emuCodeOffset = getEmuCode(proc9Offset);
|
|
||||||
memcpy(emuCodeOffset, emunand, emunand_size);
|
|
||||||
|
|
||||||
//Add the data of the found emuNAND
|
|
||||||
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4);
|
|
||||||
u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
|
|
||||||
*pos_offset = emuOffset;
|
|
||||||
*pos_header = emuHeader;
|
|
||||||
|
|
||||||
//Find and add the SDMMC struct
|
|
||||||
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
|
|
||||||
*pos_sdmmc = getSDMMC(arm9Section, section[2].size);
|
|
||||||
|
|
||||||
//Calculate offset for the hooks
|
|
||||||
u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
|
|
||||||
section[2].offset + (u32)section[2].address;
|
|
||||||
|
|
||||||
//Add emuNAND hooks
|
|
||||||
u32 emuRead,
|
|
||||||
emuWrite;
|
|
||||||
|
|
||||||
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
|
|
||||||
*(u16 *)emuRead = nandRedir[0];
|
|
||||||
*((u16 *)emuRead + 1) = nandRedir[1];
|
|
||||||
*((u32 *)emuRead + 1) = branchOffset;
|
|
||||||
*(u16 *)emuWrite = nandRedir[0];
|
|
||||||
*((u16 *)emuWrite + 1) = nandRedir[1];
|
|
||||||
*((u32 *)emuWrite + 1) = branchOffset;
|
|
||||||
|
|
||||||
//Set MPU for emu code region
|
|
||||||
u32 *mpuOffset = getMPU(arm9Section, section[2].size);
|
|
||||||
*mpuOffset = mpuPatch[0];
|
|
||||||
*(mpuOffset + 6) = mpuPatch[1];
|
|
||||||
*(mpuOffset + 9) = mpuPatch[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
|
|
||||||
{
|
|
||||||
//Calculate offset for the firmlaunch code
|
|
||||||
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
|
||||||
|
|
||||||
//Calculate offset for the fOpen function
|
|
||||||
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
|
|
||||||
|
|
||||||
//Copy firmlaunch code
|
|
||||||
memcpy(rebootOffset, reboot, reboot_size);
|
|
||||||
|
|
||||||
//Put the fOpen offset in the right location
|
|
||||||
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
|
|
||||||
*pos_fopen = fOpenOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void injectLoader(void)
|
|
||||||
{
|
|
||||||
u32 loaderSize;
|
|
||||||
|
|
||||||
void *loaderOffset = getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderSize);
|
|
||||||
|
|
||||||
//Check that the injector CXI isn't larger than the original
|
|
||||||
if((u32)injector_size <= loaderSize)
|
|
||||||
{
|
{
|
||||||
memcpy(loaderOffset, injector, injector_size);
|
patchArm11SvcAccessChecks(arm11SvcHandler);
|
||||||
|
patchK11ModuleChecks(arm11Section1, section[1].size, &freeK11Space);
|
||||||
//Patch content size and ExeFS size to match the repaced loader's ones
|
patchP9AccessChecks(process9Offset, process9Size);
|
||||||
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
|
|
||||||
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchTwlAgbFirm(u32 firmType)
|
static inline void patchLegacyFirm(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
|
u8 *arm9Section = (u8 *)firm + section[3].offset;
|
||||||
|
|
||||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
if(console)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
arm9Loader((u8 *)firm + section[3].offset, 0);
|
arm9Loader(arm9Section);
|
||||||
firm->arm9Entry = (u8 *)0x801301C;
|
firm->arm9Entry = (u8 *)0x801301C;
|
||||||
}
|
}
|
||||||
|
|
||||||
const patchData twlPatches[] = {
|
applyLegacyFirmPatches((u8 *)firm, firmType);
|
||||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
|
||||||
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
|
||||||
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
|
||||||
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
|
||||||
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
|
||||||
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
|
||||||
},
|
|
||||||
agbPatches[] = {
|
|
||||||
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
|
||||||
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
#ifdef DEV
|
||||||
if the matching option was enabled (keep it as last) */
|
//Apply UNITINFO patch
|
||||||
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
|
if(MULTICONFIG(DEVOPTIONS) == 1) patchUnitInfoValueSet(arm9Section, section[3].size);
|
||||||
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(7));
|
#endif
|
||||||
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
|
}
|
||||||
|
|
||||||
//Patch
|
static inline void patch1x2xNativeAndSafeFirm(void)
|
||||||
for(u32 i = 0; i < numPatches; i++)
|
{
|
||||||
|
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||||
|
|
||||||
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
switch(patches[i].type)
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
|
arm9Loader(arm9Section);
|
||||||
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
|
|
||||||
|
patchFirmWrites(arm9Section, section[2].size);
|
||||||
|
}
|
||||||
|
else patchOldFirmWrites(arm9Section, section[2].size);
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
if(MULTICONFIG(DEVOPTIONS) != 2)
|
||||||
|
{
|
||||||
|
//Kernel9/Process9 debugging
|
||||||
|
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
|
||||||
|
patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEV
|
||||||
|
static inline void copySection0AndInjectSystemModules(FirmwareType firmType)
|
||||||
|
{
|
||||||
|
u32 srcModuleSize,
|
||||||
|
dstModuleSize;
|
||||||
|
|
||||||
|
for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
|
||||||
|
src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
|
||||||
|
{
|
||||||
|
srcModuleSize = *(u32 *)(src + 0x104) * 0x200;
|
||||||
|
const char *moduleName = (char *)(src + 0x200);
|
||||||
|
|
||||||
|
char fileName[30] = "/luma/sysmodules/";
|
||||||
|
const char *ext = ".cxi";
|
||||||
|
|
||||||
|
//Read modules from files if they exist
|
||||||
|
concatenateStrings(fileName, moduleName);
|
||||||
|
concatenateStrings(fileName, ext);
|
||||||
|
|
||||||
|
u32 fileSize = fileRead(dst, fileName, 2 * srcModuleSize);
|
||||||
|
if(fileSize) dstModuleSize = fileSize;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
case 0:
|
const void *module;
|
||||||
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
|
||||||
break;
|
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||||
case 2:
|
{
|
||||||
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
|
module = injector;
|
||||||
case 1:
|
dstModuleSize = injector_size;
|
||||||
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
|
}
|
||||||
break;
|
else
|
||||||
|
{
|
||||||
|
module = src;
|
||||||
|
dstModuleSize = srcModuleSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, module, dstModuleSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
static inline void launchFirm(u32 bootType)
|
static inline void copySection0AndInjectSystemModules(void)
|
||||||
{
|
{
|
||||||
//Copy firm partitions to respective memory locations
|
u32 srcModuleSize,
|
||||||
for(u32 i = 0; i < 4 && section[i].size; i++)
|
dstModuleSize;
|
||||||
memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
|
|
||||||
|
for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address;
|
||||||
|
src < srcEnd; src += srcModuleSize, dst += dstModuleSize)
|
||||||
|
{
|
||||||
|
srcModuleSize = *(u32 *)(src + 0x104) * 0x200;
|
||||||
|
const char *moduleName = (const char *)(src + 0x200);
|
||||||
|
|
||||||
|
const void *module;
|
||||||
|
|
||||||
|
if(memcmp(moduleName, "loader", 6) == 0)
|
||||||
|
{
|
||||||
|
module = injector;
|
||||||
|
dstModuleSize = injector_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module = src;
|
||||||
|
dstModuleSize = srcModuleSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, module, dstModuleSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void launchFirm(FirmwareType firmType)
|
||||||
|
{
|
||||||
|
#ifdef DEV
|
||||||
|
//Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs
|
||||||
|
u32 sectionNum;
|
||||||
|
if(firmType != SAFE_FIRM && firmType != NATIVE_FIRM1X2X)
|
||||||
|
{
|
||||||
|
copySection0AndInjectSystemModules(firmType);
|
||||||
|
sectionNum = 1;
|
||||||
|
}
|
||||||
|
else sectionNum = 0;
|
||||||
|
#else
|
||||||
|
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
||||||
|
u32 sectionNum;
|
||||||
|
if(firmType == NATIVE_FIRM)
|
||||||
|
{
|
||||||
|
copySection0AndInjectSystemModules();
|
||||||
|
sectionNum = 1;
|
||||||
|
}
|
||||||
|
else sectionNum = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Copy FIRM sections to respective memory locations
|
||||||
|
for(; sectionNum < 4 && section[sectionNum].size != 0; sectionNum++)
|
||||||
|
memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size);
|
||||||
|
|
||||||
//Determine the ARM11 entry to use
|
//Determine the ARM11 entry to use
|
||||||
vu32 *arm11;
|
vu32 *arm11;
|
||||||
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
|
if(isFirmlaunch) arm11 = (u32 *)0x1FFFFFFC;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
deinitScreens();
|
deinitScreens();
|
||||||
@@ -406,6 +594,10 @@ static inline void launchFirm(u32 bootType)
|
|||||||
//Set ARM11 kernel entrypoint
|
//Set ARM11 kernel entrypoint
|
||||||
*arm11 = (u32)firm->arm11Entry;
|
*arm11 = (u32)firm->arm11Entry;
|
||||||
|
|
||||||
//Final jump to arm9 kernel
|
//Ensure that all memory transfers have completed and that the caches have been flushed
|
||||||
|
flushEntireDCache();
|
||||||
|
flushEntireICache();
|
||||||
|
|
||||||
|
//Final jump to ARM9 kernel
|
||||||
((void (*)())firm->arm9Entry)();
|
((void (*)())firm->arm9Entry)();
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
* firm.h
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||||
|
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||||
|
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
||||||
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
||||||
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
||||||
|
|
||||||
@@ -26,20 +46,16 @@ typedef struct firmHeader {
|
|||||||
u8 reserved2[0x30];
|
u8 reserved2[0x30];
|
||||||
firmSectionHeader section[4];
|
firmSectionHeader section[4];
|
||||||
} firmHeader;
|
} firmHeader;
|
||||||
|
|
||||||
|
static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource);
|
||||||
|
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
|
||||||
|
static inline void patchLegacyFirm(FirmwareType firmType);
|
||||||
|
static inline void patch1x2xNativeAndSafeFirm(void);
|
||||||
|
|
||||||
typedef struct patchData {
|
#ifdef DEV
|
||||||
u32 offset[2];
|
static inline void copySection0AndInjectSystemModules(FirmwareType firmType);
|
||||||
union {
|
#else
|
||||||
u8 type0[8];
|
static inline void copySection0AndInjectSystemModules(void);
|
||||||
u16 type1;
|
#endif
|
||||||
} patch;
|
|
||||||
u32 type;
|
|
||||||
} patchData;
|
|
||||||
|
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
static inline void launchFirm(FirmwareType firmType);
|
||||||
static inline void patchNativeFirm(u32 emuNAND, u32 emuHeader, u32 a9lhSetup);
|
|
||||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader);
|
|
||||||
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset);
|
|
||||||
static inline void injectLoader(void);
|
|
||||||
static inline void patchTwlAgbFirm(u32 firmType);
|
|
||||||
static inline void launchFirm(u32 bootType);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user