Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a840f2c79 | ||
|
|
4eaf791849 | ||
|
|
be0f50b19c | ||
|
|
f30b7b9fb3 | ||
|
|
6a0f332e3c | ||
|
|
16530d3a52 | ||
|
|
20af9c6750 | ||
|
|
fee9f6b427 | ||
|
|
57d03d6333 | ||
|
|
0075fe2aa0 | ||
|
|
d54417ac0a | ||
|
|
648801d432 | ||
|
|
2be2826b0b | ||
|
|
37a9fa1bf4 | ||
|
|
65af93c8ce | ||
|
|
8353b84944 | ||
|
|
d6a89db495 | ||
|
|
f156aa8cdb | ||
|
|
f9adbcc9d9 | ||
|
|
cf8696ac70 | ||
|
|
9c5766f649 | ||
|
|
c9701f93b9 | ||
|
|
56e54cd110 | ||
|
|
55836b48af | ||
|
|
09bfdb9ee1 | ||
|
|
1c2e8dec11 | ||
|
|
506b16db37 | ||
|
|
8f03234e58 | ||
|
|
44b5e10323 | ||
|
|
48303604b0 | ||
|
|
ab2ddbc2ee | ||
|
|
9495bf30bf | ||
|
|
a4899a1bec | ||
|
|
882c6cf0d4 | ||
|
|
a5e18c82d1 | ||
|
|
22a8661fe1 | ||
|
|
8258a98647 | ||
|
|
76dde0e6db | ||
|
|
1a39cb27e4 | ||
|
|
95d2d0a6bd | ||
|
|
98d4345858 | ||
|
|
1e4431dcc9 | ||
|
|
348b175994 | ||
|
|
76f057dafb | ||
|
|
188400c5a9 | ||
|
|
a74d9c6d3e | ||
|
|
f8bcfb2f58 | ||
|
|
d63fc2bc82 | ||
|
|
8e31784996 | ||
|
|
f27cdb4543 | ||
|
|
a39adc8ac1 | ||
|
|
97bef66018 | ||
|
|
bb5518b0f6 | ||
|
|
ac73a96ce2 | ||
|
|
7075004e58 | ||
|
|
ddf8ba5116 | ||
|
|
f46773ba64 | ||
|
|
f67d333457 | ||
|
|
4116c1e00f | ||
|
|
bc1aa15dd7 | ||
|
|
ecd27f7eaa | ||
|
|
618ce671ac | ||
|
|
2a6a655804 | ||
|
|
33436ae2a6 | ||
|
|
9f2b66ac51 | ||
|
|
df93e4797e | ||
|
|
538d1dec77 | ||
|
|
2492c8273a | ||
|
|
d358df48a6 | ||
|
|
f619dafff1 | ||
|
|
0419fc4e30 | ||
|
|
13317b9548 | ||
|
|
18db70a669 | ||
|
|
f79923814d | ||
|
|
c92de03a5f | ||
|
|
3f356da879 | ||
|
|
9efac01c86 | ||
|
|
ca2622af7c | ||
|
|
aa8e0bda8c | ||
|
|
c79f11ee99 | ||
|
|
04d0770b90 | ||
|
|
fbf8a1b6d9 | ||
|
|
a3cb6a622d | ||
|
|
0790a3ceb3 | ||
|
|
4fa12f90fc | ||
|
|
d5d56e7634 | ||
|
|
a964089df4 | ||
|
|
5fd5b4da89 | ||
|
|
322a7050aa | ||
|
|
b7f4ac02c8 | ||
|
|
009f61a8b6 | ||
|
|
26d0cafb39 | ||
|
|
bd1d4a77fe | ||
|
|
f235bc83a8 | ||
|
|
9c6b540905 | ||
|
|
d2e911a58e | ||
|
|
9344a7b434 | ||
|
|
cd194fa5b2 | ||
|
|
49c0ab65df | ||
|
|
8f9c1305e4 | ||
|
|
d4193ec11d | ||
|
|
6b9b0472bc | ||
|
|
7e74258363 | ||
|
|
f6483ec602 | ||
|
|
36c1da1d61 | ||
|
|
6bcb1f8679 | ||
|
|
62932a9639 | ||
|
|
a4629e4b65 | ||
|
|
a0c2b43b34 | ||
|
|
3907c46980 | ||
|
|
7e7ab124a3 | ||
|
|
cfc6cf24bf | ||
|
|
46e9cb6b23 | ||
|
|
ba14efe1f4 | ||
|
|
3d8f62d38f | ||
|
|
3edaf0af64 | ||
|
|
9273a88db7 | ||
|
|
37ba2c15de | ||
|
|
557f2057f7 | ||
|
|
6b5cc93780 | ||
|
|
9760191af8 | ||
|
|
8845e4dd20 | ||
|
|
8cf823f548 | ||
|
|
2538769f3a | ||
|
|
89fca38807 | ||
|
|
dcc0eed69c | ||
|
|
817475257e | ||
|
|
f2861058ba | ||
|
|
5d2a7315d5 | ||
|
|
1520ab7555 | ||
|
|
d4d0fbd73b | ||
|
|
ddb8e98e95 | ||
|
|
fd69b4169f | ||
|
|
b48e0b5c5b | ||
|
|
31e2243c5c | ||
|
|
da0ee2e442 | ||
|
|
b88dc9ac6a | ||
|
|
9f78d7f62b | ||
|
|
e67c6ed3ee | ||
|
|
2e111ca91b | ||
|
|
62d51fd99d | ||
|
|
a9289b1f21 | ||
|
|
d42e938232 | ||
|
|
3d3dcb1f28 | ||
|
|
82143212ce | ||
|
|
7246a2664e | ||
|
|
1291f2520a | ||
|
|
042ecf5343 | ||
|
|
6e54dcc24c | ||
|
|
91378ef3c1 | ||
|
|
0377cbd2b4 | ||
|
|
786ecf4fe4 | ||
|
|
0fbdee313f | ||
|
|
9b8e2b933d | ||
|
|
cc64ef9670 | ||
|
|
31ff6a1da8 | ||
|
|
94532e9cea | ||
|
|
3f93bc5988 | ||
|
|
39ca23d609 | ||
|
|
47a9c1b576 | ||
|
|
d819cfd58f | ||
|
|
17828273a5 | ||
|
|
2363817265 | ||
|
|
b31018ab17 | ||
|
|
c610ec3319 | ||
|
|
b71dedccfc | ||
|
|
9ccfacd06d | ||
|
|
12b561a27d | ||
|
|
cc41003e1c | ||
|
|
3d534c9a81 | ||
|
|
24de7c5272 | ||
|
|
a1b2ea2c5b | ||
|
|
19d68b6df4 | ||
|
|
2ab41dbd01 | ||
|
|
da30c0b0f0 | ||
|
|
005684d865 | ||
|
|
da1eff82ba | ||
|
|
a17311c955 | ||
|
|
e1d0602f25 | ||
|
|
2ff9718510 | ||
|
|
33af9cfe09 | ||
|
|
79709a7ae7 | ||
|
|
a796a70d01 | ||
|
|
53e2ef24f1 | ||
|
|
c0059c83ac | ||
|
|
37eb21d297 | ||
|
|
52a18831a7 | ||
|
|
0d7cca7b20 | ||
|
|
bea73c51ae | ||
|
|
0c68750056 | ||
|
|
ae8ea7da16 | ||
|
|
69762c5dce | ||
|
|
901d4992c0 | ||
|
|
4d47d891d1 | ||
|
|
a7046909ec | ||
|
|
4bc95979de | ||
|
|
949d219c72 | ||
|
|
9a3d9aed30 | ||
|
|
4d99143da0 | ||
|
|
461035b212 | ||
|
|
0694ea8367 | ||
|
|
427a05997d | ||
|
|
84d736c2eb | ||
|
|
a16d1ebe33 | ||
|
|
43f3c84316 | ||
|
|
44cafe3f46 | ||
|
|
76d7a035bd | ||
|
|
a5b638ae7b | ||
|
|
174089e4f3 | ||
|
|
4d219813fe | ||
|
|
a798f453d2 | ||
|
|
6ec21611c0 | ||
|
|
31f4419eec | ||
|
|
60d136f9b5 | ||
|
|
0ba7f9dba0 | ||
|
|
0ac6db006a | ||
|
|
26dd61e4e6 | ||
|
|
dda11206db | ||
|
|
e8565d30a9 | ||
|
|
2d4c103854 | ||
|
|
d0b9e36908 |
19
.github/ISSUE_TEMPLATE.md
vendored
19
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,12 +1,13 @@
|
||||
<!--
|
||||
-- THIS IS NOT A SUPPORT FORUM! For support go here:
|
||||
-- Luma3DS GBATemp thread: https://gbatemp.net/threads/luma3ds-noob-proof-3ds-custom-firmware.411110/
|
||||
-- Nintendo Hacking: https://discord.gg/MjzatM8y
|
||||
-- Nintendo Homebrew: https://discord.gg/MjzatM8
|
||||
--
|
||||
-- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752
|
||||
--
|
||||
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
|
||||
--
|
||||
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting
|
||||
-- If you're using an emu/redNAND anything related to that must also be installed to sysNAND.
|
||||
-- If you're using an emu/redNAND try installing anything on it to sysNAND.
|
||||
-- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
|
||||
--
|
||||
-- Luma updaters that don't support Boot9Strap/Sighax won't work.
|
||||
@@ -19,7 +20,7 @@
|
||||
|
||||
**SysNAND version (+emu/redNAND version if applicable):**
|
||||
|
||||
[e.g. 11.4.0-37U SysNAND, 11.4.0-37J EmuNAND]
|
||||
[e.g. 11.6.0-39U SysNAND, 11.6.0-39J EmuNAND]
|
||||
|
||||
**Entrypoint (How/what you're using to boot Luma3DS):**
|
||||
|
||||
@@ -27,7 +28,7 @@
|
||||
|
||||
**Luma3DS version:**
|
||||
|
||||
[e.g. 7.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
|
||||
[e.g. 8.1.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
|
||||
<!--You can check which version you're on in System Settings. It will be on the bottom right of the top screen.-->
|
||||
|
||||
|
||||
@@ -52,9 +53,7 @@ Use EmuNAND FIRM if booting with R: ( )
|
||||
|
||||
Enable loading external FIRMs and modules: ( )
|
||||
<!--Firmware (.bin) files are not required by Luma, or NTR CFW anymore.
|
||||
-- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card and disabling this option.-->
|
||||
|
||||
Use custom path: ( )
|
||||
-- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card or /rw/luma on CTRNAND and disabling this option.-->
|
||||
|
||||
Enable game patching: ( )
|
||||
|
||||
@@ -66,6 +65,8 @@ Patch ARM9 access: ( )
|
||||
|
||||
Set developer UNITINFO: ( )
|
||||
|
||||
Disable ARM11 exception handlers: ( )
|
||||
|
||||
--
|
||||
|
||||
|
||||
@@ -84,6 +85,6 @@ Set developer UNITINFO: ( )
|
||||
|
||||
|
||||
**Dump file:**
|
||||
<!--If the issue leads to a crash you can generate a crash dump by checking the "Enable exception handlers" option.
|
||||
<!--If the issue leads to a crash you must uncheck the "Disable ARM11 exception handlers" option.
|
||||
-- The error message will tell you where the dump is.
|
||||
-- Zip the dmp file and drag & drop it below.-->
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,18 +1,16 @@
|
||||
.vscode
|
||||
out
|
||||
build
|
||||
arm11/build
|
||||
sysmodules/loader/build
|
||||
sysmodules/rosalina/build
|
||||
chainloader/build
|
||||
rosalina/build
|
||||
exceptions/arm9/build
|
||||
exceptions/arm11/build
|
||||
.vscode
|
||||
.vscode/**
|
||||
*.bin
|
||||
*.firm
|
||||
*.o
|
||||
*.d
|
||||
*.elf
|
||||
*.cxi
|
||||
*.bmp
|
||||
*.dmp
|
||||
.DS_Store
|
||||
59
Makefile
59
Makefile
@@ -11,26 +11,44 @@ endif
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := Luma3DS
|
||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/')
|
||||
version_major := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f1 -d.)
|
||||
version_minor := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f2 -d.)
|
||||
version_build := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f3 -d.)
|
||||
commit := $(shell git rev-parse --short=8 HEAD)
|
||||
is_release := 0
|
||||
|
||||
ifeq ($(strip $(revision)),)
|
||||
revision := v0.0.0-0
|
||||
version_major := 0
|
||||
version_minor := 0
|
||||
version_build := 0
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(commit)),)
|
||||
commit := 0
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(version_build)),)
|
||||
version_build := 0
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(shell git describe --tags --match v[0-9]* | grep -)),)
|
||||
is_release := 1
|
||||
endif
|
||||
|
||||
dir_source := source
|
||||
dir_patches := patches
|
||||
dir_arm11 := arm11
|
||||
dir_chainloader := chainloader
|
||||
dir_exceptions := exceptions
|
||||
dir_arm9_exceptions := $(dir_exceptions)/arm9
|
||||
dir_k11_extension := k11_extension
|
||||
dir_sysmodules := sysmodules
|
||||
dir_loader := $(dir_sysmodules)/loader
|
||||
dir_rosalina := $(dir_sysmodules)/rosalina
|
||||
dir_sm := $(dir_sysmodules)/sm
|
||||
dir_pxi := $(dir_sysmodules)/pxi
|
||||
dir_build := build
|
||||
dir_out := out
|
||||
|
||||
@@ -42,10 +60,9 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/mmuHook.bin.o $(dir_build)/k11MainHook.bin.o $(dir_build)/svcConnectToPortInitHook.bin.o $(dir_build)/svcCustomBackdoor.bin.o\
|
||||
$(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o
|
||||
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o
|
||||
|
||||
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi
|
||||
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi $(dir_build)/sm.cxi $(dir_build)/pxi.cxi
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
@@ -65,8 +82,11 @@ clean:
|
||||
@$(MAKE) -C $(dir_arm11) clean
|
||||
@$(MAKE) -C $(dir_chainloader) clean
|
||||
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||
@$(MAKE) -C $(dir_k11_extension) clean
|
||||
@$(MAKE) -C $(dir_loader) clean
|
||||
@$(MAKE) -C $(dir_rosalina) clean
|
||||
@$(MAKE) -C $(dir_sm) clean
|
||||
@$(MAKE) -C $(dir_pxi) clean
|
||||
@rm -rf $(dir_out) $(dir_build)
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
@@ -74,21 +94,25 @@ clean:
|
||||
.PHONY: $(dir_arm11)
|
||||
.PHONY: $(dir_chainloader)
|
||||
.PHONY: $(dir_arm9_exceptions)
|
||||
.PHONY: $(dir_k11_extension)
|
||||
.PHONY: $(dir_loader)
|
||||
.PHONY: $(dir_rosalina)
|
||||
.PHONY: $(dir_sm)
|
||||
.PHONY: $(dir_pxi)
|
||||
|
||||
|
||||
$(dir_out)/$(name)$(revision).7z: all
|
||||
@mkdir -p "$(@D)"
|
||||
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
||||
@[ -f "$@" ] || 7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser -xr!.DS_Store
|
||||
|
||||
$(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf
|
||||
$(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf $(dir_build)/k11_extension.bin
|
||||
@mkdir -p "$(@D)"
|
||||
@firmtool build $@ -D $^ -A 0x1FF60000 -C XDMA XDMA NDMA
|
||||
@firmtool build $@ -D $^ -A 0x18180000 0x18000000 -C XDMA XDMA NDMA XDMA
|
||||
|
||||
$(dir_build)/modules.bin: $(modules)
|
||||
@mkdir -p "$(@D)"
|
||||
cat $^ > $@
|
||||
|
||||
|
||||
$(dir_build)/arm11.elf: $(dir_arm11)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
@@ -96,6 +120,10 @@ $(dir_build)/arm11.elf: $(dir_arm11)
|
||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/k11_extension.bin: $(dir_k11_extension)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/loader.cxi: $(dir_loader)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
@@ -104,6 +132,14 @@ $(dir_build)/rosalina.cxi: $(dir_rosalina)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/sm.cxi: $(dir_sm)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/pxi.cxi: $(dir_pxi)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
@@ -121,9 +157,10 @@ $(dir_build)/%.bin: $(dir_patches)/%.s
|
||||
|
||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||
$(dir_build)/firm.o: $(dir_build)/modules.bin
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell du -b $(dir_build)/modules.bin | cut -f1)"
|
||||
$(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\
|
||||
-DVERSION_BUILD="$(version_build)" -DISRELEASE="$(is_release)" -DCOMMIT_HASH="0x$(commit)"
|
||||
$(dir_build)/firm.o: $(dir_build)/modules.bin
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell wc -c $(dir_build)/modules.bin | tr -d [:space:][:alpha:][:punct:])"
|
||||
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
|
||||
To use it, you will need a console capable of running homebrew software on the ARM9 processor. We recommend [Plailect's guide](https://3ds.guide/) for details on how to get your system ready.
|
||||
|
||||
Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Start+Select` (see the release notes).
|
||||
Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Down+Select` (see the [release notes](https://github.com/AuroraWright/Luma3DS/releases/tag/v8.0)).
|
||||
|
||||
---
|
||||
|
||||
@@ -15,9 +15,9 @@ Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Start+Se
|
||||
|
||||
First you need to clone the repository with: `git clone https://github.com/AuroraWright/Luma3DS.git`
|
||||
To compile, you'll need [armips](https://github.com/Kingcom/armips) and a build of a recent commit of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. You'll also need to install [firmtool](https://github.com/TuxSH/firmtool), its README contains installation instructions.
|
||||
For now, you'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit.
|
||||
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` and everything should work!
|
||||
You'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit.
|
||||
Here are [Windows](https://buildbot.orphis.net/armips/) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!) and [makerom](https://github.com/Steveice10/buildtools/tree/master/3ds) (thanks @Steveice10!).
|
||||
Run `make` and everything should work!
|
||||
You can find the compiled files in the `out` folder.
|
||||
|
||||
---
|
||||
|
||||
@@ -11,6 +11,6 @@ SECTIONS
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; }
|
||||
|
||||
__stack_top__ = 0x1FFFF000;
|
||||
__stack_top__ = 0x1FFFE000;
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ extern u32 prepareForFirmlaunchSize;
|
||||
|
||||
extern volatile Arm11Operation operation;
|
||||
|
||||
static void initScreensSequence(u32 brightnessLevel)
|
||||
static void initScreens(u32 brightnessLevel, struct fb *fbs)
|
||||
{
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
@@ -70,10 +70,13 @@ static void initScreensSequence(u32 brightnessLevel)
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = 0x18300000;
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046C = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
@@ -104,7 +107,8 @@ static void initScreensSequence(u32 brightnessLevel)
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056C = (u32)fbs[1].bottom;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
@@ -178,8 +182,8 @@ void main(void)
|
||||
{
|
||||
case ARM11_READY:
|
||||
continue;
|
||||
case INIT_SCREENS_SEQUENCE:
|
||||
initScreensSequence(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
case INIT_SCREENS:
|
||||
initScreens(*(vu32 *)ARM11_PARAMETERS_ADDRESS, (struct fb *)(ARM11_PARAMETERS_ADDRESS + 4));
|
||||
break;
|
||||
case SETUP_FRAMEBUFFERS:
|
||||
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
|
||||
@@ -54,7 +54,7 @@ struct fb {
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INIT_SCREENS_SEQUENCE = 0,
|
||||
INIT_SCREENS = 0,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
|
||||
@@ -28,9 +28,8 @@
|
||||
#include "cache.h"
|
||||
#include "firm.h"
|
||||
|
||||
void main(int argc, char **argv)
|
||||
void main(int argc, char **argv, Firm *firm)
|
||||
{
|
||||
Firm *firm = (Firm *)0x20001000;
|
||||
char *argvPassed[2],
|
||||
absPath[24 + 255];
|
||||
struct fb fbs[2];
|
||||
|
||||
@@ -56,5 +56,5 @@ disableMpuAndJumpToEntrypoints:
|
||||
@ Jump to the ARM9 entrypoint
|
||||
mov r0, r4
|
||||
mov r1, r5
|
||||
ldr r2, =0x1BEEF
|
||||
ldr r2, =0x3BEEF
|
||||
bx r6
|
||||
|
||||
@@ -116,7 +116,10 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type)
|
||||
//Copy header (actually optimized by the compiler)
|
||||
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
|
||||
|
||||
if(ARESCREENSINITIALIZED) i2cWriteRegister(I2C_DEV_MCU, 0x22, 1 << 0); //Shutdown LCD
|
||||
|
||||
((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);
|
||||
}
|
||||
|
||||
@@ -39,3 +39,7 @@ typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
|
||||
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
||||
|
||||
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
|
||||
|
||||
25
exceptions/exception_dump_parser.py → exceptions/exception_dump_parser/luma3ds_exception_dump_parser/__main__.py
Normal file → Executable file
25
exceptions/exception_dump_parser.py → exceptions/exception_dump_parser/luma3ds_exception_dump_parser/__main__.py
Normal file → Executable file
@@ -90,8 +90,15 @@ def makeRegisterLine(A, rA, B, 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)")
|
||||
faultStatusSources = {
|
||||
0b1:'Alignment', 0b100:'Instruction cache maintenance operation fault',
|
||||
0b1100:'External Abort on translation - First-level', 0b1110:'External Abort on translation - Second-level',
|
||||
0b101:'Translation - Section', 0b111:'Translation - Page', 0b11:'Access bit - Section', 0b110:'Access bit - Page',
|
||||
0b1001:'Domain - Section', 0b1011:'Domain - Page', 0b1101:'Permission - Section', 0b1111:'Permission - Page',
|
||||
0b1000:'Precise External Abort', 0b10110:'Imprecise External Abort', 0b10:'Debug event'
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main(args=None):
|
||||
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
|
||||
parser.add_argument("filename")
|
||||
args = parser.parse_args()
|
||||
@@ -134,6 +141,11 @@ if __name__ == "__main__":
|
||||
typeDetailsStr = " (VFP exception)"
|
||||
|
||||
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
|
||||
|
||||
if processor == 11 and exceptionType >= 2:
|
||||
xfsr = registers[18] if exceptionType == 2 else registers[17]
|
||||
print("Fault status: " + faultStatusSources[xfsr & 0xf])
|
||||
|
||||
if additionalDataSize != 0:
|
||||
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
|
||||
|
||||
@@ -143,6 +155,9 @@ if __name__ == "__main__":
|
||||
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])))
|
||||
|
||||
if processor == 11 and exceptionType == 3:
|
||||
print("{0:<15}{1:<20}Access type: {2}".format("FAR", "{0:08x}".format(registers[19]), "Write" if registers[17] & (1 << 11) != 0 else "Read"))
|
||||
|
||||
thumb = registers[16] & 0x20 != 0
|
||||
addr = registers[15] - codeDumpSize + (2 if thumb else 4)
|
||||
|
||||
@@ -151,8 +166,9 @@ if __name__ == "__main__":
|
||||
objdump_res = ""
|
||||
try:
|
||||
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
|
||||
if os.name == "nt":
|
||||
path = ''.join((path[1], ':', path[2:])).replace('/', '\\')
|
||||
|
||||
if os.name == "nt" and path[0] == '/':
|
||||
path = ''.join((path[1], ':', path[2:]))
|
||||
|
||||
objdump_res = subprocess.check_output((
|
||||
path, "-marm", "-b", "binary",
|
||||
@@ -167,3 +183,6 @@ if __name__ == "__main__":
|
||||
|
||||
print("\nStack dump:\n")
|
||||
print(hexdump(registers[13], stackDump))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
exceptions/exception_dump_parser/setup.py
Normal file
13
exceptions/exception_dump_parser/setup.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='luma3ds_exception_dump_parser',
|
||||
version='1.2',
|
||||
url='https://github.com/AuroraWright/Luma3DS',
|
||||
author='TuxSH',
|
||||
license='GPLv3',
|
||||
description='Parses Luma3DS exception dumps',
|
||||
install_requires=[''],
|
||||
packages=find_packages(),
|
||||
entry_points={'console_scripts': ['luma3ds_exception_dump_parser=luma3ds_exception_dump_parser.__main__:main']},
|
||||
)
|
||||
@@ -6,7 +6,7 @@ endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := kernel_extension
|
||||
name := k11_extension
|
||||
|
||||
dir_source := source
|
||||
dir_include := include
|
||||
@@ -14,9 +14,9 @@ dir_build := build
|
||||
|
||||
ARCH := -mcpu=mpcore -mfpu=vfp
|
||||
ASFLAGS := $(ARCH)
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -I$(dir_include) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math \
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -I$(dir_include) -fno-builtin -std=c11 -Wno-main -g -flto -O2 -ffast-math \
|
||||
-mword-relocations -ffunction-sections -fdata-sections
|
||||
LDFLAGS := -nostdlib -Wl,--gc-sections $(ARCH)
|
||||
LDFLAGS := -nostdlib -Wl,--gc-sections,--nmagic $(ARCH)
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
36
k11_extension/include/config.h
Normal file
36
k11_extension/include/config.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#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))
|
||||
|
||||
#define CONFIG(a) (((cfwInfo.config >> (a)) & 1) != 0)
|
||||
#define MULTICONFIG(a) ((cfwInfo.multiConfig >> (2 * (a))) & 3)
|
||||
#define BOOTCONFIG(a, b) ((cfwInfo.bootConfig >> (a)) & (b))
|
||||
|
||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
|
||||
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
|
||||
|
||||
enum multiOptions
|
||||
{
|
||||
DEFAULTEMU = 0,
|
||||
BRIGHTNESS,
|
||||
SPLASH,
|
||||
PIN,
|
||||
NEWCPU
|
||||
};
|
||||
|
||||
enum singleOptions
|
||||
{
|
||||
AUTOBOOTEMU = 0,
|
||||
USEEMUFIRM,
|
||||
LOADEXTFIRMSANDMODULES,
|
||||
PATCHGAMES,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHUNITINFO,
|
||||
DISABLEARM11EXCHANDLERS
|
||||
};
|
||||
@@ -24,18 +24,16 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "synchronization.h"
|
||||
#include "utils.h"
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "globals.h"
|
||||
#include "kernel.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern SGI0Handler_t SGI0Handler;
|
||||
extern KRecursiveLock dbgParamsLock;
|
||||
extern u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId;
|
||||
|
||||
void executeFunctionOnCores(SGI0Handler_t handler, u8 targetList, u8 targetListFilter)
|
||||
{
|
||||
u32 coreID = getCurrentCoreID();
|
||||
SGI0Handler = handler;
|
||||
|
||||
if(targetListFilter == 0 && (targetListFilter & (1 << coreID)) != 0)
|
||||
__asm__ volatile("cpsie i"); // make sure interrupts aren't masked
|
||||
MPCORE_GID_SGI = (targetListFilter << 24) | (targetList << 16) | 0;
|
||||
}
|
||||
KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this, u32 interruptID);
|
||||
KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this, u32 interruptID);
|
||||
KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this, u32 interruptID);
|
||||
@@ -28,10 +28,9 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
bool isExceptionFatal(u32 spsr);
|
||||
bool isExceptionFatal(u32 spsr, u32 *regs, u32 index);
|
||||
bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr);
|
||||
|
||||
|
||||
void FIQHandler(void);
|
||||
void undefinedInstructionHandler(void);
|
||||
void prefetchAbortHandler(void);
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
|
||||
extern KRecursiveLock *criticalSectionLock;
|
||||
@@ -55,6 +56,7 @@ extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
|
||||
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||
extern void (*SleepThread)(s64 ns);
|
||||
extern Result (*CloseHandle)(Handle handle);
|
||||
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
|
||||
extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
|
||||
extern Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
|
||||
extern Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);
|
||||
@@ -63,6 +65,7 @@ extern Result (*SendSyncRequest)(Handle handle);
|
||||
extern Result (*OpenProcess)(Handle *out, u32 processId);
|
||||
extern Result (*GetProcessId)(u32 *out, Handle process);
|
||||
extern Result (*DebugActiveProcess)(Handle *out, u32 processId);
|
||||
extern Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
|
||||
extern Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
|
||||
|
||||
extern void (*flushDataCacheRange)(void *addr, u32 len);
|
||||
@@ -75,11 +78,9 @@ extern bool (*kernelToUsrMemcpy8)(void *dst, const void *src, u32 len);
|
||||
extern bool (*kernelToUsrMemcpy32)(u32 *dst, const u32 *src, u32 len);
|
||||
extern s32 (*kernelToUsrStrncpy)(char *dst, const char *src, u32 len);
|
||||
|
||||
extern Result (*CustomBackdoor)(void *function, ...);
|
||||
|
||||
extern void (*svcFallbackHandler)(u8 svcId);
|
||||
extern void (*kernelpanic)(void);
|
||||
extern void (*PostprocessSvc)(void);
|
||||
extern void (*officialPostProcessSvc)(void);
|
||||
|
||||
extern Result (*SignalDebugEvent)(DebugEventType type, u32 info, ...);
|
||||
|
||||
@@ -89,11 +90,23 @@ extern u32 *exceptionStackTop;
|
||||
extern u32 TTBCR;
|
||||
extern u32 L1MMUTableAddrs[4];
|
||||
|
||||
extern u32 kernelVersion;
|
||||
extern void *kernelUsrCopyFuncsStart, *kernelUsrCopyFuncsEnd;
|
||||
|
||||
extern bool *isDevUnit;
|
||||
|
||||
extern vu8 *configPage;
|
||||
extern u32 kernelVersion;
|
||||
extern FcramLayout fcramLayout;
|
||||
|
||||
extern KCoreContext *coreCtxs;
|
||||
|
||||
extern void *originalHandlers[8];
|
||||
extern u32 nbSection0Modules;
|
||||
|
||||
extern u8 __start__[], __end__[], __bss_start__[], __bss_end__[];
|
||||
|
||||
extern Result (*InterruptManager__MapInterrupt)(InterruptManager *manager, KBaseInterruptEvent *iEvent, u32 interruptID,
|
||||
u32 coreID, u32 priority, bool disableUponReceipt, bool levelHighActive);
|
||||
extern InterruptManager *interruptManager;
|
||||
extern KBaseInterruptEvent *customInterruptEvent;
|
||||
|
||||
@@ -101,7 +114,7 @@ extern void (*initFPU)(void);
|
||||
extern void (*mcuReboot)(void);
|
||||
extern void (*coreBarrier)(void);
|
||||
|
||||
typedef struct PACKED CfwInfo
|
||||
typedef struct CfwInfo
|
||||
{
|
||||
char magic[4];
|
||||
|
||||
@@ -112,10 +125,13 @@ typedef struct PACKED CfwInfo
|
||||
|
||||
u32 commitHash;
|
||||
|
||||
u32 config;
|
||||
u16 configFormatVersionMajor, configFormatVersionMinor;
|
||||
u32 config, multiConfig, bootConfig;
|
||||
u64 hbldr3dsxTitleId;
|
||||
u32 rosalinaMenuCombo;
|
||||
} CfwInfo;
|
||||
|
||||
extern CfwInfo cfwInfo;
|
||||
|
||||
extern u32 rosalinaState;
|
||||
extern bool hasStartedRosalinaNetworkFuncsOnce;
|
||||
extern vu32 rosalinaState;
|
||||
extern bool hasStartedRosalinaNetworkFuncsOnce;
|
||||
@@ -56,6 +56,6 @@ void SessionInfo_ChangeVtable(KSession *session);
|
||||
void SessionInfo_Add(KSession *session, const char *name);
|
||||
void SessionInfo_Remove(KSession *session);
|
||||
|
||||
bool doLangEmu(Result *res, Handle handle, u32 *cmdbuf);
|
||||
bool doLangEmu(Result *res, u32 *cmdbuf);
|
||||
Result doPublishToProcessHook(Handle handle, u32 *cmdbuf);
|
||||
bool doErrfThrowHook(u32 *cmdbuf);
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern u32 kernelVersion;
|
||||
|
||||
struct KMutex;
|
||||
struct KProcessO3DS;
|
||||
struct KProcessN3DS;
|
||||
@@ -204,7 +206,7 @@ typedef struct PACKED ALIGN(4) KThread
|
||||
KMutexLinkedList *mutexList;
|
||||
KLinkedList mutexesUsed;
|
||||
s32 dynamicPriority;
|
||||
u32 processor;
|
||||
u32 coreId;
|
||||
KPreemptionTimer *preemptionTimer;
|
||||
u32 unknown_1;
|
||||
bool isAlive;
|
||||
@@ -948,6 +950,7 @@ typedef struct KCoreContext
|
||||
} KCoreContext;
|
||||
|
||||
static KCoreContext * const currentCoreContext = (KCoreContext *)0xFFFF1000;
|
||||
extern KCoreContext *coreCtxs;
|
||||
|
||||
#define DEFINE_CONSOLE_SPECIFIC_STRUCTS(console, nbCores)
|
||||
/* 60 */
|
||||
@@ -1121,25 +1124,42 @@ typedef union KCacheMaintenanceInterruptEvent
|
||||
KCacheMaintenanceInterruptEventO3DS O3DS;
|
||||
} KCacheMaintenanceInterruptEvent;
|
||||
|
||||
typedef struct FcramLayout
|
||||
{
|
||||
void *applicationAddr;
|
||||
u32 applicationSize;
|
||||
void *systemAddr;
|
||||
u32 systemSize;
|
||||
void *baseAddr;
|
||||
u32 baseSize;
|
||||
} FcramLayout;
|
||||
|
||||
extern bool isN3DS;
|
||||
extern void *officialSVCs[0x7E];
|
||||
|
||||
extern u32 kernelVersion;
|
||||
#define KPROCESS_OFFSETOF(field) (isN3DS ? offsetof(KProcessN3DS, field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(KProcessO3DS8x, field) :\
|
||||
offsetof(KProcessO3DSPre8x, field)))
|
||||
#define KPROCESSRELATED_OFFSETOFF(classname, field) (isN3DS ? offsetof(classname##N3DS, field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(classname##O3DS8x, field) :\
|
||||
offsetof(classname##O3DSPre8x, field)))
|
||||
|
||||
#define KPROCESS_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
|
||||
#define KPROCESSRELATED_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\
|
||||
&(obj)->O3DSPre8x.field ))
|
||||
&(obj)->O3DSPre8x.field))
|
||||
|
||||
#define KPROCESS_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
|
||||
#define KPROCESSRELATED_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\
|
||||
(type *)(&(obj)->O3DSPre8x.field) ))
|
||||
(type *)(&(obj)->O3DSPre8x.field)))
|
||||
|
||||
#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field))
|
||||
#define KPROCESS_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcess, field)
|
||||
#define KPROCESS_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
|
||||
#define KPROCESS_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
|
||||
#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field))
|
||||
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR_TYPE(type, obj, field))
|
||||
|
||||
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR(type, obj, field))
|
||||
#define KPROCESSHWINFO_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcessHwInfo, field)
|
||||
#define KPROCESSHWINFO_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
|
||||
#define KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
|
||||
#define KPROCESSHWINFO_GET_RVALUE(obj, field) *(KPROCESSHWINFO_GET_PTR(obj, field))
|
||||
#define KPROCESSHWINFO_GET_RVALUE_TYPE(type, obj, field) *(KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field))
|
||||
|
||||
static inline u32 idOfProcess(KProcess *process)
|
||||
{
|
||||
@@ -1166,6 +1186,20 @@ static inline KDebug *debugOfProcess(KProcess *process)
|
||||
return KPROCESS_GET_RVALUE(process, debug);
|
||||
}
|
||||
|
||||
static inline const char *classNameOfAutoObject(KAutoObject *object)
|
||||
{
|
||||
const char *name;
|
||||
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
object->vtable->GetClassToken(&tok, object);
|
||||
name = tok.name;
|
||||
}
|
||||
else
|
||||
name = object->vtable->GetClassName(object);
|
||||
return name;
|
||||
}
|
||||
|
||||
extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
|
||||
|
||||
static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj)
|
||||
@@ -33,5 +33,6 @@
|
||||
|
||||
extern void *officialSVCs[0x7E];
|
||||
|
||||
void postprocessSvc(void);
|
||||
void svcDefaultHandler(u8 svcId);
|
||||
void *svcHook(u8 *pageEnd);
|
||||
@@ -25,6 +25,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <3ds/types.h>
|
||||
|
||||
void installKernelExtension(void);
|
||||
#include "utils.h"
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
void CustomBackdoor(void *function, ...);
|
||||
@@ -26,13 +26,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PA_FROM_VA_PTR(addr) PA_PTR(convertVAToPA(addr))
|
||||
|
||||
#include "utils.h"
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
Result svc0x2F(void *function, ...); // custom backdoor before kernel ext. is installed (and only before!)
|
||||
|
||||
void *convertVAToPA(const void *VA);
|
||||
|
||||
extern u8 kernel_extension[];
|
||||
extern u32 kernel_extension_size;
|
||||
Result GetHandleInfoHookWrapper(u32 dummy, Handle handle, u32 type);
|
||||
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type);
|
||||
@@ -30,6 +30,5 @@
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
extern u32 rosalinaState;
|
||||
bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId);
|
||||
Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3);
|
||||
@@ -30,4 +30,4 @@
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
void SetWifiEnabled(bool enable);
|
||||
Result SetWifiEnabled(bool enable);
|
||||
@@ -34,6 +34,14 @@ typedef KSchedulableInterruptEvent* (*SGI0Handler_t)(KBaseInterruptEvent *this,
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CCHDIFIJ.html
|
||||
void executeFunctionOnCores(SGI0Handler_t func, u8 targetList, u8 targetListFilter);
|
||||
|
||||
void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this);
|
||||
void KThread__DebugReschedule(KThread *this, bool lock);
|
||||
bool rosalinaThreadLockPredicate(KThread *thread);
|
||||
void rosalinaRescheduleThread(KThread *thread, bool lock);
|
||||
void rosalinaLockThread(KThread *thread);
|
||||
void rosalinaLockAllThreads(void);
|
||||
void rosalinaUnlockAllThreads(void);
|
||||
|
||||
// Taken from ctrulib:
|
||||
|
||||
static inline void __dsb(void)
|
||||
@@ -59,3 +67,53 @@ static inline bool __strex(s32* addr, s32 val)
|
||||
__asm__ __volatile__("strex %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline s8 __ldrex8(s8* addr)
|
||||
{
|
||||
s8 val;
|
||||
__asm__ __volatile__("ldrexb %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline bool __strex8(s8* addr, s8 val)
|
||||
{
|
||||
bool res;
|
||||
__asm__ __volatile__("strexb %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline s16 __ldrex16(s16* addr)
|
||||
{
|
||||
s16 val;
|
||||
__asm__ __volatile__("ldrexh %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline bool __strex16(s16* addr, s16 val)
|
||||
{
|
||||
bool res;
|
||||
__asm__ __volatile__("strexh %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline u32 __get_cpsr(void)
|
||||
{
|
||||
u32 cpsr;
|
||||
__asm__ __volatile__("mrs %0, cpsr" : "=r"(cpsr));
|
||||
return cpsr;
|
||||
}
|
||||
|
||||
static inline void __set_cpsr_cx(u32 cpsr)
|
||||
{
|
||||
__asm__ __volatile__("msr cpsr_cx, %0" :: "r"(cpsr));
|
||||
}
|
||||
|
||||
static inline void __enable_irq(void)
|
||||
{
|
||||
__asm__ __volatile__("cpsie i");
|
||||
}
|
||||
|
||||
static inline void __disable_irq(void)
|
||||
{
|
||||
__asm__ __volatile__("cpsid i");
|
||||
}
|
||||
19
k11_extension/linker.ld
Normal file
19
k11_extension/linker.ld
Normal file
@@ -0,0 +1,19 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40000000;
|
||||
|
||||
__start__ = .;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
__end__ = .;
|
||||
}
|
||||
147
k11_extension/source/debug.c
Normal file
147
k11_extension/source/debug.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 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 and 7.c of GPLv3 apply 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.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "synchronization.h"
|
||||
|
||||
KRecursiveLock dbgParamsLock = { NULL };
|
||||
u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId;
|
||||
|
||||
KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
|
||||
{
|
||||
coreBarrier();
|
||||
|
||||
u32 DSCR;
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 0" : [val] "=r" (DSCR));
|
||||
DSCR |= 0x8000;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 0" :: [val] "r" (DSCR));
|
||||
|
||||
__dsb();
|
||||
coreBarrier();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void disableWatchpoint0(void)
|
||||
{
|
||||
u32 control;
|
||||
|
||||
// WCR0
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c0, 7" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (control));
|
||||
|
||||
// BCR4
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c4, 5" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (control));
|
||||
}
|
||||
|
||||
static void disableWatchpoint1(void)
|
||||
{
|
||||
u32 control;
|
||||
|
||||
// WCR1
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 7" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (control));
|
||||
|
||||
// BCR5
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c5, 5" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (control));
|
||||
}
|
||||
|
||||
KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
|
||||
{
|
||||
coreBarrier();
|
||||
|
||||
if(dbgParamWatchpointId == 0)
|
||||
disableWatchpoint0();
|
||||
else
|
||||
disableWatchpoint1();
|
||||
|
||||
__dsb();
|
||||
coreBarrier();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void setWatchpoint0WithContextId(u32 DVA, u32 WCR, u32 contextId)
|
||||
{
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
|
||||
u32 BCR =
|
||||
(1 << 21) | /* compare with context ID */
|
||||
(1 << 20) | /* linked (with a WRP in our case) */
|
||||
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
|
||||
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
disableWatchpoint0();
|
||||
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 6" :: [val] "r" (DVA));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 4" :: [val] "r" (contextId));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (WCR));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (BCR));
|
||||
|
||||
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
|
||||
}
|
||||
|
||||
static void setWatchpoint1WithContextId(u32 DVA, u32 WCR, u32 contextId)
|
||||
{
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
|
||||
u32 BCR =
|
||||
(1 << 21) | /* compare with context ID */
|
||||
(1 << 20) | /* linked (with a WRP in our case) */
|
||||
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
|
||||
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
disableWatchpoint1();
|
||||
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 6" :: [val] "r" (DVA));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 4" :: [val] "r" (contextId));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (WCR));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (BCR));
|
||||
|
||||
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
|
||||
}
|
||||
|
||||
KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
|
||||
{
|
||||
coreBarrier();
|
||||
|
||||
if(dbgParamWatchpointId == 0)
|
||||
setWatchpoint0WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId);
|
||||
else
|
||||
setWatchpoint1WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId);
|
||||
|
||||
__dsb();
|
||||
coreBarrier();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -47,6 +47,8 @@
|
||||
|
||||
push {r0-r12, lr}
|
||||
mrs r0, spsr
|
||||
mov r1, sp
|
||||
mov r2, #\index
|
||||
bl isExceptionFatal
|
||||
cmp r0, #0
|
||||
pop {r0-r12, lr}
|
||||
@@ -138,7 +140,7 @@ _commonHandler:
|
||||
mcr p15, 0, r0, c7, c10, 4 @ Drain Synchronization Barrier
|
||||
|
||||
ldr r0, =isN3DS
|
||||
ldr r0, [r0]
|
||||
ldrb r0, [r0]
|
||||
cmp r0, #0
|
||||
beq _no_L2C
|
||||
ldr r0, =(0x17e10100 | 1 << 31)
|
||||
@@ -33,8 +33,10 @@
|
||||
#define REG_DUMP_SIZE 4 * 23
|
||||
#define CODE_DUMP_SIZE 48
|
||||
|
||||
bool isExceptionFatal(u32 spsr)
|
||||
bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
|
||||
{
|
||||
if(CONFIG(DISABLEARM11EXCHANDLERS)) return false;
|
||||
|
||||
if((spsr & 0x1f) != 0x10) return true;
|
||||
|
||||
KThread *thread = currentCoreContext->objectContext.currentThread;
|
||||
@@ -51,6 +53,10 @@ bool isExceptionFatal(u32 spsr)
|
||||
thread = KPROCESS_GET_RVALUE(currentProcess, mainThread);
|
||||
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
|
||||
return false;
|
||||
|
||||
if(index == 3 && strcmp(codeSetOfProcess(currentProcess)->processName, "menu") == 0 && // workaround a Home Menu bug leading to a dabort
|
||||
regs[0] == 0x3FFF && regs[2] == 0 && regs[5] == 2 && regs[7] == 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -52,6 +52,7 @@ void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
|
||||
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||
void (*SleepThread)(s64 ns);
|
||||
Result (*CloseHandle)(Handle handle);
|
||||
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
|
||||
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
|
||||
Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
|
||||
Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);
|
||||
@@ -60,6 +61,7 @@ Result (*SendSyncRequest)(Handle handle);
|
||||
Result (*OpenProcess)(Handle *out, u32 processId);
|
||||
Result (*GetProcessId)(u32 *out, Handle process);
|
||||
Result (*DebugActiveProcess)(Handle *out, u32 processId);
|
||||
Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
|
||||
Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
|
||||
|
||||
void (*flushDataCacheRange)(void *addr, u32 len);
|
||||
@@ -72,11 +74,9 @@ bool (*kernelToUsrMemcpy8)(void *dst, const void *src, u32 len);
|
||||
bool (*kernelToUsrMemcpy32)(u32 *dst, const u32 *src, u32 len);
|
||||
s32 (*kernelToUsrStrncpy)(char *dst, const char *src, u32 len);
|
||||
|
||||
Result (*CustomBackdoor)(void *function, ...);
|
||||
|
||||
void (*svcFallbackHandler)(u8 svcId);
|
||||
void (*kernelpanic)(void);
|
||||
void (*PostprocessSvc)(void);
|
||||
void (*officialPostProcessSvc)(void);
|
||||
|
||||
Result (*SignalDebugEvent)(DebugEventType type, u32 info, ...);
|
||||
|
||||
@@ -86,11 +86,21 @@ u32 *exceptionStackTop;
|
||||
u32 TTBCR;
|
||||
u32 L1MMUTableAddrs[4];
|
||||
|
||||
u32 kernelVersion;
|
||||
void *kernelUsrCopyFuncsStart, *kernelUsrCopyFuncsEnd;
|
||||
|
||||
bool *isDevUnit;
|
||||
|
||||
vu8 *configPage;
|
||||
u32 kernelVersion;
|
||||
FcramLayout fcramLayout;
|
||||
KCoreContext *coreCtxs;
|
||||
|
||||
void *originalHandlers[8] = {NULL};
|
||||
|
||||
u32 nbSection0Modules;
|
||||
|
||||
Result (*InterruptManager__MapInterrupt)(InterruptManager *manager, KBaseInterruptEvent *iEvent, u32 interruptID,
|
||||
u32 coreID, u32 priority, bool disableUponReceipt, bool levelHighActive);
|
||||
InterruptManager *interruptManager;
|
||||
KBaseInterruptEvent *customInterruptEvent;
|
||||
|
||||
@@ -100,5 +110,5 @@ void (*coreBarrier)(void);
|
||||
|
||||
CfwInfo cfwInfo;
|
||||
|
||||
u32 rosalinaState;
|
||||
vu32 rosalinaState;
|
||||
bool hasStartedRosalinaNetworkFuncsOnce;
|
||||
@@ -182,7 +182,7 @@ void SessionInfo_ChangeVtable(KSession *session)
|
||||
session->autoObject.vtable = (Vtable__KAutoObject *)customSessionVtable;
|
||||
}
|
||||
|
||||
bool doLangEmu(Result *res, Handle handle, u32 *cmdbuf)
|
||||
bool doLangEmu(Result *res, u32 *cmdbuf)
|
||||
{
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
KRecursiveLock__Lock(&processLangemuLock);
|
||||
@@ -220,15 +220,12 @@ bool doLangEmu(Result *res, Handle handle, u32 *cmdbuf)
|
||||
else if(cmdbuf[1] == 4 && cmdbuf[2] == 0xB0000 && cmdbuf[3] == 0x4C && (attribs->mask & 0xC))
|
||||
{
|
||||
u8 *ptr = (u8 *)cmdbuf[4];
|
||||
*res = SendSyncRequest(handle);
|
||||
flushEntireDataCache(); // looks like it's needed. WTF?!
|
||||
if(*res == 0)
|
||||
{
|
||||
if(attribs->mask & 4)
|
||||
ptr[3] = attribs->country;
|
||||
if(attribs->mask & 8)
|
||||
ptr[2] = attribs->state;
|
||||
}
|
||||
if(attribs->mask & 4)
|
||||
ptr[3] = attribs->country;
|
||||
if(attribs->mask & 8)
|
||||
ptr[2] = attribs->state;
|
||||
|
||||
ptr[0] = ptr[1] = 0;
|
||||
}
|
||||
else
|
||||
skip = false;
|
||||
@@ -260,7 +257,7 @@ Result doPublishToProcessHook(Handle handle, u32 *cmdbuf)
|
||||
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
|
||||
}
|
||||
|
||||
if(terminateRosalina)
|
||||
if(terminateRosalina && nbSection0Modules == 6)
|
||||
{
|
||||
Handle rosalinaProcessHandle;
|
||||
res = OpenProcess(&rosalinaProcessHandle, 5);
|
||||
@@ -33,79 +33,93 @@
|
||||
#include "svcHandler.h"
|
||||
#include "memory.h"
|
||||
|
||||
static const u32 *const exceptionsPage = (const u32 *)0xFFFF0000;
|
||||
void *originalHandlers[8] = {NULL};
|
||||
|
||||
enum VECTORS { RESET = 0, UNDEFINED_INSTRUCTION, SVC, PREFETCH_ABORT, DATA_ABORT, RESERVED, IRQ, FIQ };
|
||||
|
||||
static void setupSGI0Handler(void)
|
||||
struct KExtParameters
|
||||
{
|
||||
for(u32 i = 0; i < getNumberOfCores(); i++)
|
||||
interruptManager->N3DS.privateInterrupts[i][0].interruptEvent = customInterruptEvent;
|
||||
u32 ALIGN(0x400) L2MMUTableFor0x40000000[256];
|
||||
u32 basePA;
|
||||
void *originalHandlers[4];
|
||||
u32 L1MMUTableAddrs[4];
|
||||
|
||||
CfwInfo cfwInfo;
|
||||
} kExtParameters = { .basePA = 0x12345678 }; // place this in .data
|
||||
|
||||
void relocateAndSetupMMU(u32 coreId, u32 *L1Table)
|
||||
{
|
||||
struct KExtParameters *p0 = (struct KExtParameters *)((u32)&kExtParameters - 0x40000000 + 0x18000000);
|
||||
struct KExtParameters *p = (struct KExtParameters *)((u32)&kExtParameters - 0x40000000 + p0->basePA);
|
||||
|
||||
if(coreId == 0)
|
||||
{
|
||||
// Relocate ourselves, and clear BSS
|
||||
memcpy((void *)p0->basePA, (const void *)0x18000000, __bss_start__ - __start__);
|
||||
memset32((u32 *)(p0->basePA + (__bss_start__ - __start__)), 0, __bss_end__ - __bss_start__);
|
||||
|
||||
// Map the kernel ext to 0x40000000
|
||||
// 4KB extended small pages: [SYS:RW USR:-- X TYP:NORMAL SHARED OUTER NOCACHE, INNER CACHED WB WA]
|
||||
for(u32 offset = 0; offset < (u32)(__end__ - __start__); offset += 0x1000)
|
||||
p->L2MMUTableFor0x40000000[offset >> 12] = (p0->basePA + offset) | 0x516;
|
||||
|
||||
__asm__ __volatile__ ("sev");
|
||||
}
|
||||
else
|
||||
__asm__ __volatile__ ("wfe");
|
||||
|
||||
// bit31 idea thanks to SALT
|
||||
// Maps physmem so that, if addr is in physmem(0, 0x30000000), it can be accessed uncached&rwx as addr|(1<<31)
|
||||
u32 attribs = 0x40C02; // supersection (rwx for all) of strongly ordered memory, shared
|
||||
for(u32 PA = 0; PA < 0x30000000; PA += 0x01000000)
|
||||
{
|
||||
u32 VA = (1 << 31) | PA;
|
||||
for(u32 i = 0; i < 16; i++)
|
||||
L1Table[i + (VA >> 20)] = PA | attribs;
|
||||
}
|
||||
|
||||
L1Table[0x40000000 >> 20] = (u32)p->L2MMUTableFor0x40000000 | 1;
|
||||
|
||||
p->L1MMUTableAddrs[coreId] = (u32)L1Table;
|
||||
}
|
||||
|
||||
static inline void **getHandlerDestination(enum VECTORS vector)
|
||||
void bindSGI0Hook(void)
|
||||
{
|
||||
u32 *branch_dst = (u32 *)decodeARMBranch((u32 *)exceptionsPage + (u32)vector);
|
||||
return (void **)(branch_dst + 2);
|
||||
if(InterruptManager__MapInterrupt(interruptManager, customInterruptEvent, 0, getCurrentCoreID(), 0, false, false) != 0)
|
||||
__asm__ __volatile__ ("bkpt 0xdead");
|
||||
}
|
||||
|
||||
static inline void swapHandlerInVeneer(enum VECTORS vector, void *handler)
|
||||
void configHook(vu8 *cfgPage)
|
||||
{
|
||||
void **dst = getHandlerDestination(vector);
|
||||
originalHandlers[(u32)vector] = *dst;
|
||||
if(handler != NULL)
|
||||
*(void**)PA_FROM_VA_PTR(dst) = handler;
|
||||
}
|
||||
configPage = cfgPage;
|
||||
|
||||
static u32 *trampo_;
|
||||
static bool **enableUserExceptionHandlersForCPUExcLoc;
|
||||
static bool enableUserExceptionHandlersForCPUExc = true;
|
||||
|
||||
static void setupSvcHandler(void)
|
||||
{
|
||||
swapHandlerInVeneer(SVC, svcHandler);
|
||||
|
||||
void **arm11SvcTable = (void**)originalHandlers[(u32)SVC];
|
||||
while(*arm11SvcTable != NULL) arm11SvcTable++; //Look for SVC0 (NULL)
|
||||
memcpy(officialSVCs, arm11SvcTable, 4 * 0x7E);
|
||||
|
||||
u32 *off;
|
||||
for(off = (u32 *)officialSVCs[0x2D]; *off != 0x65736162; off++);
|
||||
*(void **)PA_FROM_VA_PTR(arm11SvcTable + 0x2D) = officialSVCs[0x2D] = (void *)off[1];
|
||||
trampo_ = (u32 *)PA_FROM_VA_PTR(off + 3);
|
||||
|
||||
CustomBackdoor = (Result (*)(void *, ...))((u32 *)officialSVCs[0x2F] + 2);
|
||||
*(void **)PA_FROM_VA_PTR(arm11SvcTable + 0x2F) = officialSVCs[0x2F] = (void *)*((u32 *)officialSVCs[0x2F] + 1);
|
||||
|
||||
off = (u32 *)originalHandlers[(u32) SVC];
|
||||
while(*off++ != 0xE1A00009);
|
||||
svcFallbackHandler = (void (*)(u8))decodeARMBranch(off);
|
||||
for(; *off != 0xE92D000F; off++);
|
||||
PostprocessSvc = (void (*)(void))decodeARMBranch(off + 1);
|
||||
}
|
||||
|
||||
static void setupExceptionHandlers(void)
|
||||
{
|
||||
swapHandlerInVeneer(FIQ, FIQHandler);
|
||||
swapHandlerInVeneer(UNDEFINED_INSTRUCTION, undefinedInstructionHandler);
|
||||
swapHandlerInVeneer(PREFETCH_ABORT, prefetchAbortHandler);
|
||||
swapHandlerInVeneer(DATA_ABORT, dataAbortHandler);
|
||||
|
||||
setupSvcHandler();
|
||||
kernelVersion = *(vu32 *)configPage;
|
||||
*(vu32 *)(configPage + 0x40) = fcramLayout.applicationSize;
|
||||
*(vu32 *)(configPage + 0x44) = fcramLayout.systemSize;
|
||||
*(vu32 *)(configPage + 0x48) = fcramLayout.baseSize;
|
||||
*isDevUnit = true; // enable debug features
|
||||
}
|
||||
|
||||
static void findUsefulSymbols(void)
|
||||
{
|
||||
u32 *off;
|
||||
|
||||
for(off = (u32 *)0xFFFF0000; *off != 0xE1A0D002; off++);
|
||||
off += 3;
|
||||
initFPU = (void (*) (void))off;
|
||||
|
||||
for(; *off != 0xE3A0A0C2; off++);
|
||||
mcuReboot = (void (*) (void))--off;
|
||||
coreBarrier = (void (*) (void))decodeARMBranch(off - 4);
|
||||
|
||||
for(off = (u32 *)originalHandlers[2]; *off != 0xE1A00009; off++);
|
||||
svcFallbackHandler = (void (*)(u8))decodeARMBranch(off + 1);
|
||||
for(; *off != 0xE92D000F; off++);
|
||||
officialPostProcessSvc = (void (*)(void))decodeARMBranch(off + 1);
|
||||
|
||||
KProcessHandleTable__ToKProcess = (KProcess * (*)(KProcessHandleTable *, Handle))decodeARMBranch(5 + (u32 *)officialSVCs[0x76]);
|
||||
|
||||
for(off = (u32 *)KProcessHandleTable__ToKProcess; *off != 0xE28DD014; off++);
|
||||
KAutoObject__AddReference = (void (*)(KAutoObject *))decodeARMBranch(off - 1);
|
||||
for(off = (u32 *)KProcessHandleTable__ToKProcess; *off != 0xE1A00004; off++);
|
||||
KAutoObject__AddReference = (void (*)(KAutoObject *))decodeARMBranch(off + 1);
|
||||
|
||||
for(; *off != 0xE8BD80F0; off++);
|
||||
KProcessHandleTable__ToKAutoObject = (KAutoObject * (*)(KProcessHandleTable *, Handle))decodeARMBranch(off + 2);
|
||||
for(; *off != 0xE320F000; off++);
|
||||
KProcessHandleTable__ToKAutoObject = (KAutoObject * (*)(KProcessHandleTable *, Handle))decodeARMBranch(off + 1);
|
||||
|
||||
for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[9]); /* KThread::Terminate */ *off != 0xE5D42034; off++);
|
||||
off -= 2;
|
||||
@@ -121,26 +135,30 @@ static void findUsefulSymbols(void)
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x19]; *off != 0xE1A04005; off++);
|
||||
KEvent__Clear = (Result (*)(KEvent *))decodeARMBranch(off + 1);
|
||||
for(off = (u32 *)KEvent__Clear; *off != 0xE8BD8070; off++)
|
||||
for(off = (u32 *)KEvent__Clear; *off != 0xE8BD8070; off++);
|
||||
synchronizationMutex = *(KObjectMutex **)(off + 1);
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x24]; *off != 0xE59F004C; off++);
|
||||
WaitSynchronization1 = (Result (*)(void *, KThread *, KSynchronizationObject *, s64))decodeARMBranch(off + 6);
|
||||
|
||||
for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[0x33]) /* OpenProcess */ ; *off != 0xE20030FF; off++);
|
||||
KProcessHandleTable__CreateHandle = (Result (*)(KProcessHandleTable *, Handle *, KAutoObject *, u8))decodeARMBranch(off + 2);
|
||||
for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[0x33]) /* OpenProcess */ ; *off != 0xE1A05000; off++);
|
||||
KProcessHandleTable__CreateHandle = (Result (*)(KProcessHandleTable *, Handle *, KAutoObject *, u8))decodeARMBranch(off - 1);
|
||||
|
||||
for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[0x34]) /* OpenThread */; *off != 0xD9001BF7; off++);
|
||||
threadList = *(KObjectList **)(off + 1);
|
||||
|
||||
KProcessHandleTable__ToKThread = (KThread * (*)(KProcessHandleTable *, Handle))decodeARMBranch((u32 *)decodeARMBranch((u32 *)officialSVCs[0x37] + 3) /* GetThreadId */ + 5);
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x50]; off[0] != 0xE1A05000 || off[1] != 0xE2100102 || off[2] != 0x5A00000B; off++);
|
||||
InterruptManager__MapInterrupt = (Result (*)(InterruptManager *, KBaseInterruptEvent *, u32, u32, u32, bool, bool))decodeARMBranch(--off);
|
||||
interruptManager = *(InterruptManager **)(off - 4 + (off[-6] & 0xFFF) / 4);
|
||||
for(off = (u32 *)officialSVCs[0x54]; *off != 0xE8BD8008; off++);
|
||||
flushDataCacheRange = (void (*)(void *, u32))(*(u32 **)(off[1]) + 3);
|
||||
|
||||
for(off = (u32 *)officialSVCs[0x71]; *off != 0xE2101102; off++);
|
||||
KProcessHwInfo__MapProcessMemory = (Result (*)(KProcessHwInfo *, KProcessHwInfo *, void *, void *, u32))decodeARMBranch(off - 1);
|
||||
|
||||
// From 4.x to 6.x the pattern will match but the result will be wrong
|
||||
for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++);
|
||||
KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeARMBranch(off - 1);
|
||||
|
||||
@@ -149,7 +167,7 @@ static void findUsefulSymbols(void)
|
||||
for(; *off != 0xE320F000; off++);
|
||||
KObjectMutex__ErrorOccured = (void (*)(void))decodeARMBranch(off + 1);
|
||||
|
||||
for(off = (u32 *)originalHandlers[(u32) DATA_ABORT]; *off != (u32)exceptionStackTop; off++);
|
||||
for(off = (u32 *)originalHandlers[4]; *off != (u32)exceptionStackTop; off++);
|
||||
kernelUsrCopyFuncsStart = (void *)off[1];
|
||||
kernelUsrCopyFuncsEnd = (void *)off[2];
|
||||
|
||||
@@ -190,6 +208,7 @@ static void findUsefulSymbols(void)
|
||||
decodeARMBranch((u32 *)officialSVCs[0x01] + 5);
|
||||
SleepThread = (void (*)(s64))officialSVCs[0x0A];
|
||||
CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
|
||||
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x29] + 3);
|
||||
GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3);
|
||||
GetProcessInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2B] + 3);
|
||||
GetThreadInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2C] + 3);
|
||||
@@ -198,26 +217,25 @@ static void findUsefulSymbols(void)
|
||||
OpenProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x33] + 3);
|
||||
GetProcessId = (Result (*)(u32 *, Handle))decodeARMBranch((u32 *)officialSVCs[0x35] + 3);
|
||||
DebugActiveProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x60] + 3);
|
||||
UnmapProcessMemory = (Result (*)(Handle, void *, u32))officialSVCs[0x72];
|
||||
KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1);
|
||||
|
||||
for(off = (u32 *)svcFallbackHandler; *off != 0xE8BD4010; off++);
|
||||
kernelpanic = (void (*)(void))off;
|
||||
kernelpanic = (void (*)(void))decodeARMBranch(off + 1);
|
||||
|
||||
for(off = (u32 *)0xFFFF0000; off[0] != 0xE3A01002 || off[1] != 0xE3A00004; off++);
|
||||
SignalDebugEvent = (Result (*)(DebugEventType type, u32 info, ...))decodeARMBranch(off + 2);
|
||||
|
||||
for(; *off != 0x96007F9; off++);
|
||||
isDevUnit = *(bool **)(off - 1);
|
||||
enableUserExceptionHandlersForCPUExcLoc = (bool **)(off + 1);
|
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
// Shitty/lazy heuristic but it works on even 4.5, so...
|
||||
u32 textStart = ((u32)originalHandlers[(u32) SVC]) & ~0xFFFF;
|
||||
u32 rodataStart = (u32)(interruptManager->N3DS.privateInterrupts[0][6].interruptEvent->vtable) & ~0xFFF;
|
||||
|
||||
u32 textStart = ((u32)originalHandlers[2]) & ~0xFFFF;
|
||||
u32 rodataStart = (u32)(interruptManager->N3DS.privateInterrupts[1][0x1D].interruptEvent->vtable) & ~0xFFF;
|
||||
u32 textSize = rodataStart - textStart;
|
||||
for(off = (u32 *)textStart; off < (u32 *)(textStart + textSize) - 3; off++)
|
||||
for(off = (u32 *)textStart; off < (u32 *)(textStart + textSize - 12); off++)
|
||||
{
|
||||
if(off[0] == 0xE5D13034 && off[1] == 0xE1530002)
|
||||
KScheduler__AdjustThread = (void (*)(KScheduler *, KThread *, u32))off;
|
||||
@@ -232,79 +250,33 @@ static void findUsefulSymbols(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct Parameters
|
||||
void main(FcramLayout *layout, KCoreContext *ctxs)
|
||||
{
|
||||
void (*SGI0HandlerCallback)(struct Parameters *, u32 *);
|
||||
InterruptManager *interruptManager;
|
||||
u32 *L2MMUTable; // bit31 mapping
|
||||
struct KExtParameters *p = &kExtParameters;
|
||||
u32 TTBCR_;
|
||||
s64 nb;
|
||||
|
||||
void (*initFPU)(void);
|
||||
void (*mcuReboot)(void);
|
||||
void (*coreBarrier)(void);
|
||||
layout->systemSize -= __end__ - __start__;
|
||||
fcramLayout = *layout;
|
||||
coreCtxs = ctxs;
|
||||
|
||||
u32 TTBCR;
|
||||
u32 L1MMUTableAddrs[4];
|
||||
|
||||
u32 kernelVersion;
|
||||
|
||||
CfwInfo cfwInfo;
|
||||
};
|
||||
|
||||
static void enableDebugFeatures(void)
|
||||
{
|
||||
*isDevUnit = true; // for debug SVCs and user exc. handlers, etc.
|
||||
*(bool **)PA_FROM_VA_PTR(enableUserExceptionHandlersForCPUExcLoc) = &enableUserExceptionHandlersForCPUExc;
|
||||
|
||||
u32 *off;
|
||||
for(off = (u32 *)officialSVCs[0x7C]; off[0] != 0xE5D00001 || off[1] != 0xE3500000; off++);
|
||||
*(u32 *)PA_FROM_VA_PTR(off + 2) = 0xE1A00000; // in case 6: beq -> nop
|
||||
|
||||
for(off = (u32 *)DebugActiveProcess; *off != 0xE3110001; off++);
|
||||
*(u32 *)PA_FROM_VA_PTR(off) = 0xE3B01001; // tst r1, #1 -> movs r1, #1
|
||||
}
|
||||
|
||||
static void doOtherPatches(void)
|
||||
{
|
||||
u32 *kpanic = (u32 *)kernelpanic;
|
||||
*(u32 *)PA_FROM_VA_PTR(kpanic) = 0xE12FFF7E; // bkpt 0xFFFE
|
||||
|
||||
u32 *off;
|
||||
for(off = (u32 *)ControlMemory; (off[0] & 0xFFF0FFFF) != 0xE3500001 || (off[1] & 0xFFFF0FFF) != 0x13A00000; off++);
|
||||
off -= 2;
|
||||
|
||||
/*
|
||||
Here we replace currentProcess->processID == 1 by additionnalParameter == 1.
|
||||
This patch should be generic enough to work even on firmware version 5.0.
|
||||
|
||||
It effectively changes the prototype of the ControlMemory function which
|
||||
only caller is the svc 0x01 handler on OFW.
|
||||
*/
|
||||
*(u32 *)PA_FROM_VA_PTR(off) = 0xE59D0000 | (*off & 0x0000F000) | (8 + computeARMFrameSize((u32 *)ControlMemory)); // ldr r0, [sp, #(frameSize + 8)]
|
||||
|
||||
}
|
||||
|
||||
void main(volatile struct Parameters *p)
|
||||
{
|
||||
__asm__ __volatile__("mrc p15, 0, %0, c2, c0, 2" : "=r"(TTBCR_));
|
||||
TTBCR = TTBCR_;
|
||||
isN3DS = getNumberOfCores() == 4;
|
||||
interruptManager = p->interruptManager;
|
||||
|
||||
initFPU = p->initFPU;
|
||||
mcuReboot = p->mcuReboot;
|
||||
coreBarrier = p->coreBarrier;
|
||||
|
||||
TTBCR = p->TTBCR;
|
||||
memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16);
|
||||
exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20));
|
||||
kernelVersion = p->kernelVersion;
|
||||
cfwInfo = p->cfwInfo;
|
||||
|
||||
setupSGI0Handler();
|
||||
setupExceptionHandlers();
|
||||
memcpy(originalHandlers + 1, p->originalHandlers, 16);
|
||||
void **arm11SvcTable = (void**)originalHandlers[2];
|
||||
while(*arm11SvcTable != NULL) arm11SvcTable++; //Look for SVC0 (NULL)
|
||||
memcpy(officialSVCs, arm11SvcTable, 4 * 0x7E);
|
||||
|
||||
findUsefulSymbols();
|
||||
enableDebugFeatures();
|
||||
doOtherPatches();
|
||||
|
||||
GetSystemInfo(&nb, 26, 0);
|
||||
nbSection0Modules = (u32)nb;
|
||||
|
||||
rosalinaState = 0;
|
||||
hasStartedRosalinaNetworkFuncsOnce = false;
|
||||
*trampo_ = (u32)ConnectToPortHookWrapper;
|
||||
}
|
||||
@@ -22,40 +22,51 @@
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.text
|
||||
.arm
|
||||
.section .text.start
|
||||
.balign 4
|
||||
.global _start
|
||||
_start:
|
||||
b start
|
||||
b startPhys
|
||||
|
||||
.global svc0x2F
|
||||
.type svc0x2F, %function
|
||||
svc0x2F:
|
||||
@ custom backdoor before kernel ext. is installed
|
||||
svc 0x2F
|
||||
b _bindSGI0Hook
|
||||
b configHook
|
||||
|
||||
b undefinedInstructionHandler
|
||||
b svcHandler
|
||||
b prefetchAbortHandler
|
||||
b dataAbortHandler
|
||||
|
||||
.word __end__
|
||||
.word kExtParameters
|
||||
.word 1 @ enableUserExceptionHandlersForCPUExc
|
||||
|
||||
b KThread__DebugReschedule
|
||||
start:
|
||||
@ Only core0 executes this, the other cores are running coreBarrier
|
||||
|
||||
@ Skipped instruction:
|
||||
str r1, [r4, #0x8]
|
||||
|
||||
push {r0-r12, lr}
|
||||
|
||||
sub r0, r4, #8
|
||||
sub r1, r8, #0x8000
|
||||
bl main
|
||||
|
||||
pop {r0-r12, pc}
|
||||
|
||||
startPhys:
|
||||
push {r0-r12, lr}
|
||||
mrc p15, 0, r0, c0, c0, 5 @ CPUID register
|
||||
and r0, #3
|
||||
mov r1, r2
|
||||
bl relocateAndSetupMMU
|
||||
pop {r0-r12, lr}
|
||||
mov r12, #0x20000000 @ instruction that has been patched
|
||||
bx lr
|
||||
|
||||
.global convertVAToPA
|
||||
.type convertVAToPA, %function
|
||||
convertVAToPA:
|
||||
@ needs to be executed in supervisor mode
|
||||
mov r1, #0x1000
|
||||
sub r1, #1
|
||||
and r2, r0, r1
|
||||
bic r0, r1
|
||||
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
|
||||
tst r0, #1 @ failure bit
|
||||
bic r0, r1
|
||||
addeq r0, r2
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
||||
.section .data
|
||||
|
||||
.p2align 12
|
||||
.global kernel_extension
|
||||
kernel_extension: .incbin "build/kernel_extension.bin"
|
||||
.p2align 12
|
||||
kernel_extension_end:
|
||||
|
||||
.global kernel_extension_size
|
||||
kernel_extension_size: .word kernel_extension_end - kernel_extension
|
||||
_bindSGI0Hook:
|
||||
push {r0-r12, lr}
|
||||
bl bindSGI0Hook
|
||||
pop {r0-r12, pc}
|
||||
@@ -24,11 +24,14 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
#include "synchronization.h"
|
||||
#include "svc.h"
|
||||
#include "svc/ControlMemory.h"
|
||||
#include "svc/GetHandleInfo.h"
|
||||
#include "svc/GetSystemInfo.h"
|
||||
#include "svc/GetProcessInfo.h"
|
||||
#include "svc/GetThreadInfo.h"
|
||||
#include "svc/GetSystemInfo.h"
|
||||
#include "svc/GetCFWInfo.h"
|
||||
#include "svc/ConnectToPort.h"
|
||||
#include "svc/SendSyncRequest.h"
|
||||
@@ -37,6 +40,7 @@
|
||||
#include "svc/SetWifiEnabled.h"
|
||||
#include "svc/Backdoor.h"
|
||||
#include "svc/KernelSetState.h"
|
||||
#include "svc/CustomBackdoor.h"
|
||||
#include "svc/MapProcessMemoryEx.h"
|
||||
#include "svc/UnmapProcessMemoryEx.h"
|
||||
#include "svc/ControlService.h"
|
||||
@@ -45,24 +49,11 @@
|
||||
|
||||
void *officialSVCs[0x7E] = {NULL};
|
||||
|
||||
static inline void yieldDuringRosalinaMenu(void)
|
||||
{
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
|
||||
u64 titleId = codeSetOfProcess(currentProcess)->titleId;
|
||||
u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)titleId;
|
||||
while((rosalinaState & 1) && idOfProcess(currentProcess) >= 6 &&
|
||||
(highTitleId != 0x00040130 || (highTitleId == 0x00040130 && (lowTitleId == 0x1A02 || lowTitleId == 0x1C02))))
|
||||
SleepThread(25 * 1000 * 1000LL);
|
||||
}
|
||||
|
||||
void signalSvcEntry(u8 *pageEnd)
|
||||
{
|
||||
u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5);
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
|
||||
yieldDuringRosalinaMenu();
|
||||
|
||||
if(svcId == 0xFE)
|
||||
svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x3FFFFFFF. We don't support catching svcIds >= 0x100 atm either
|
||||
|
||||
@@ -76,8 +67,6 @@ void signalSvcReturn(u8 *pageEnd)
|
||||
u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5);
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
|
||||
yieldDuringRosalinaMenu();
|
||||
|
||||
if(svcId == 0xFE)
|
||||
svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x1FFFFFFF. We don't support catching svcIds >= 0x100 atm either
|
||||
|
||||
@@ -86,6 +75,17 @@ void signalSvcReturn(u8 *pageEnd)
|
||||
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId);
|
||||
}
|
||||
|
||||
void postprocessSvc(void)
|
||||
{
|
||||
KThread *currentThread = currentCoreContext->objectContext.currentThread;
|
||||
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread))
|
||||
rosalinaRescheduleThread(currentThread, true);
|
||||
|
||||
officialPostProcessSvc();
|
||||
}
|
||||
|
||||
static bool doingVeryShittyPmResLimitWorkaround = false; // I feel dirty
|
||||
|
||||
void *svcHook(u8 *pageEnd)
|
||||
{
|
||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
||||
@@ -97,6 +97,15 @@ void *svcHook(u8 *pageEnd)
|
||||
{
|
||||
case 0x01:
|
||||
return ControlMemoryHookWrapper;
|
||||
case 0x17:
|
||||
if(strcmp(codeSetOfProcess(currentProcess)->processName, "pm") == 0) // only called twice in pm, by the same function
|
||||
{
|
||||
*(vu32 *)(configPage + 0x44) += __end__ - __start__;
|
||||
doingVeryShittyPmResLimitWorkaround = true;
|
||||
}
|
||||
return officialSVCs[0x17];
|
||||
case 0x29:
|
||||
return GetHandleInfoHookWrapper;
|
||||
case 0x2A:
|
||||
return GetSystemInfoHookWrapper;
|
||||
case 0x2B:
|
||||
@@ -115,6 +124,13 @@ void *svcHook(u8 *pageEnd)
|
||||
return SetGpuProt;
|
||||
case 0x5A:
|
||||
return SetWifiEnabled;
|
||||
case 0x79:
|
||||
if(doingVeryShittyPmResLimitWorkaround)
|
||||
{
|
||||
*(vu32 *)(configPage + 0x44) -= __end__ - __start__;
|
||||
doingVeryShittyPmResLimitWorkaround = false;
|
||||
}
|
||||
return officialSVCs[0x79];
|
||||
case 0x7B:
|
||||
return Backdoor;
|
||||
case 0x7C:
|
||||
@@ -42,20 +42,12 @@ Result ControlService(ServiceOp op, u32 varg1, u32 varg2)
|
||||
KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTable, (Handle)varg2);
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7; // invalid handle
|
||||
else if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
obj->vtable->GetClassToken(&tok, obj);
|
||||
if(tok.flags == 0x95)
|
||||
session = ((KServerSession *)obj)->parentSession;
|
||||
else if(tok.flags == 0xA5)
|
||||
session = ((KClientSession *)obj)->parentSession;
|
||||
}
|
||||
else
|
||||
{ // not the exact same tests but it should work
|
||||
if(strcmp(obj->vtable->GetClassName(obj), "KServerSession") == 0)
|
||||
{
|
||||
// not the exact same tests but it should work
|
||||
if(strcmp(classNameOfAutoObject(obj), "KServerSession") == 0)
|
||||
session = ((KServerSession *)obj)->parentSession;
|
||||
else if(strcmp(obj->vtable->GetClassName(obj), "KClientSession") == 0)
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KClientSession") == 0)
|
||||
session = ((KClientSession *)obj)->parentSession;
|
||||
}
|
||||
|
||||
@@ -22,34 +22,17 @@
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.section .text.start
|
||||
.text
|
||||
.arm
|
||||
.balign 4
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
.global CustomBackdoor
|
||||
.type CustomBackdoor, %function
|
||||
CustomBackdoor:
|
||||
push {r4, lr}
|
||||
|
||||
mrc p15, 0, r4, c0, c0, 5 @ CPUID register
|
||||
and r4, #3
|
||||
cmp r4, #1
|
||||
beq _core1_only
|
||||
|
||||
_waitLoop:
|
||||
wfe
|
||||
ldr r0, =_setupFinished
|
||||
ldr r0, [r0]
|
||||
cmp r0, #0
|
||||
beq _waitLoop
|
||||
b end
|
||||
|
||||
_core1_only:
|
||||
bl main
|
||||
ldr r0, =_setupFinished
|
||||
str r4, [r0]
|
||||
sev
|
||||
|
||||
end:
|
||||
mov r4, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
blx r4
|
||||
pop {r4, pc}
|
||||
|
||||
.bss
|
||||
.balign 4
|
||||
_setupFinished: .word 0
|
||||
62
k11_extension/source/svc/GetHandleInfo.c
Normal file
62
k11_extension/source/svc/GetHandleInfo.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 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 and 7.c of GPLv3 apply 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.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "svc/GetThreadInfo.h"
|
||||
#include "memory.h"
|
||||
|
||||
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
|
||||
{
|
||||
if(type == 0x10000) // KDebug and KProcess: get context ID
|
||||
{
|
||||
KProcessHwInfo *hwInfo;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
KAutoObject *obj;
|
||||
if(handle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
|
||||
KAutoObject__AddReference(obj);
|
||||
}
|
||||
else
|
||||
obj = KProcessHandleTable__ToKAutoObject(handleTable, handle);
|
||||
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7;
|
||||
|
||||
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
|
||||
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
|
||||
hwInfo = hwInfoOfProcess((KProcess *)obj);
|
||||
else
|
||||
hwInfo = NULL;
|
||||
|
||||
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
|
||||
|
||||
obj->vtable->DecrementReferenceCount(obj);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return GetHandleInfo(out, handle, type);
|
||||
}
|
||||
@@ -73,12 +73,12 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
|
||||
*out = (s64)(u64)(u32)codeSetOfProcess(process)->dataSection.section.loadAddress;
|
||||
break;
|
||||
case 0x10008:
|
||||
*out = (isN3DS ? hwInfoOfProcess(process)->N3DS.translationTableBase :
|
||||
(kernelVersion >= SYSTEM_VERSION(2, 44, 6)
|
||||
? hwInfoOfProcess(process)->O3DS8x.translationTableBase
|
||||
: hwInfoOfProcess(process)->O3DSPre8x.translationTableBase)
|
||||
) & ~((1 << (14 - TTBCR)) - 1);
|
||||
{
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
u32 ttb = KPROCESSHWINFO_GET_RVALUE(hwInfo, translationTableBase);
|
||||
*out = ttb & ~((1 << (14 - TTBCR)) - 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = 0xD8E007ED; // invalid enum value
|
||||
break;
|
||||
@@ -46,18 +46,35 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
|
||||
*out = cfwInfo.commitHash;
|
||||
break;
|
||||
case 2:
|
||||
*out = (cfwInfo.configFormatVersionMajor << 16) | cfwInfo.configFormatVersionMinor;
|
||||
break;
|
||||
case 3:
|
||||
*out = cfwInfo.config;
|
||||
break;
|
||||
case 3: // isRelease
|
||||
case 4:
|
||||
*out = cfwInfo.multiConfig;
|
||||
break;
|
||||
case 5:
|
||||
*out = cfwInfo.bootConfig;
|
||||
break;
|
||||
|
||||
case 0x100:
|
||||
*out = (s64)cfwInfo.hbldr3dsxTitleId;
|
||||
break;
|
||||
case 0x101:
|
||||
*out = cfwInfo.rosalinaMenuCombo;
|
||||
break;
|
||||
|
||||
case 0x200: // isRelease
|
||||
*out = cfwInfo.flags & 1;
|
||||
break;
|
||||
case 4: // isN3DS
|
||||
case 0x201: // isN3DS
|
||||
*out = (cfwInfo.flags >> 4) & 1;
|
||||
break;
|
||||
case 5: // isSafeMode
|
||||
case 0x202: // isSafeMode
|
||||
*out = (cfwInfo.flags >> 5) & 1;
|
||||
break;
|
||||
case 6: // isSdMode
|
||||
case 0x203: // isSdMode
|
||||
*out = (cfwInfo.flags >> 6) & 1;
|
||||
break;
|
||||
default:
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "svc/KernelSetState.h"
|
||||
#include "synchronization.h"
|
||||
#include "ipc.h"
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define MAX_DEBUG 3
|
||||
@@ -107,6 +108,11 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
|
||||
if(rosalinaState & 2)
|
||||
hasStartedRosalinaNetworkFuncsOnce = true;
|
||||
|
||||
if(rosalinaState & 1)
|
||||
rosalinaLockAllThreads();
|
||||
else if(varg1 & 1)
|
||||
rosalinaUnlockAllThreads();
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x10001:
|
||||
@@ -122,7 +128,7 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
|
||||
processLangemuAttributes[i].state = (u8)(varg1 >> 24);
|
||||
processLangemuAttributes[i].country = (u8)(varg1 >> 16);
|
||||
processLangemuAttributes[i].language = (u8)(varg1 >> 8);
|
||||
processLangemuAttributes[i].region = (u8)(varg1 >> 4);
|
||||
processLangemuAttributes[i].region = (u8)((varg1 >> 4) & 0xf);
|
||||
processLangemuAttributes[i].mask = (u8)(varg1 & 0xf);
|
||||
}
|
||||
else
|
||||
@@ -137,7 +143,41 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
|
||||
res = SetSyscallDebugEventMask(varg1, (bool)varg2, (const u32 *)varg3);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x10003:
|
||||
{
|
||||
executeFunctionOnCores(enableMonitorModeDebugging, 0xF, 0);
|
||||
break;
|
||||
}
|
||||
case 0x10004:
|
||||
{
|
||||
KRecursiveLock__Lock(&dbgParamsLock);
|
||||
dbgParamWatchpointId = varg1;
|
||||
executeFunctionOnCores(disableWatchpoint, 0xF, 0);
|
||||
KRecursiveLock__Unlock(&dbgParamsLock);
|
||||
break;
|
||||
}
|
||||
case 0x10005:
|
||||
{
|
||||
KRecursiveLock__Lock(&dbgParamsLock);
|
||||
dbgParamWatchpointId = 0;
|
||||
dbgParamDVA = varg1;
|
||||
dbgParamWCR = varg2;
|
||||
dbgParamContextId = varg3;
|
||||
executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0);
|
||||
KRecursiveLock__Unlock(&dbgParamsLock);
|
||||
break;
|
||||
}
|
||||
case 0x10006:
|
||||
{
|
||||
KRecursiveLock__Lock(&dbgParamsLock);
|
||||
dbgParamWatchpointId = 1;
|
||||
dbgParamDVA = varg1;
|
||||
dbgParamWCR = varg2;
|
||||
dbgParamContextId = varg3;
|
||||
executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0);
|
||||
KRecursiveLock__Unlock(&dbgParamsLock);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
res = KernelSetState(type, varg1, varg2, varg3);
|
||||
@@ -37,15 +37,8 @@ Result SendSyncRequestHook(Handle handle)
|
||||
bool skip = false;
|
||||
Result res = 0;
|
||||
|
||||
bool isValidClientSession = false;
|
||||
if(clientSession != NULL && kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
clientSession->syncObject.autoObject.vtable->GetClassToken(&tok, &clientSession->syncObject.autoObject);
|
||||
isValidClientSession = tok.flags == 0xA5;
|
||||
}
|
||||
else if(clientSession != NULL) // not the exact same test but it should work
|
||||
isValidClientSession = strcmp(clientSession->syncObject.autoObject.vtable->GetClassName(&clientSession->syncObject.autoObject), "KClientSession");
|
||||
// not the exact same test but it should work
|
||||
bool isValidClientSession = clientSession != NULL && strcmp(classNameOfAutoObject(&clientSession->syncObject.autoObject), "KClientSession") == 0;
|
||||
|
||||
if(isValidClientSession)
|
||||
{
|
||||
@@ -54,7 +47,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x10042:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:pm") == 0)
|
||||
if(info != NULL && kernelVersion >= SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
|
||||
{
|
||||
res = doPublishToProcessHook(handle, cmdbuf);
|
||||
skip = true;
|
||||
@@ -73,7 +66,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && (strcmp(info->name, "cfg:u") == 0 || strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk2
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -91,7 +84,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && (strcmp(info->name, "cfg:u") == 0 || strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // SecureInfoGetRegion
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -112,7 +105,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x50100:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:") == 0)
|
||||
if(info != NULL && (strcmp(info->name, "srv:") == 0 || (kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)))
|
||||
{
|
||||
char name[9] = { 0 };
|
||||
memcpy(name, cmdbuf + 1, 8);
|
||||
@@ -126,7 +119,8 @@ Result SendSyncRequestHook(Handle handle)
|
||||
outClientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, (Handle)cmdbuf[3]);
|
||||
if(outClientSession != NULL)
|
||||
{
|
||||
SessionInfo_Add(outClientSession->parentSession, name);
|
||||
if(strcmp(classNameOfAutoObject(&outClientSession->syncObject.autoObject), "KClientSession") == 0)
|
||||
SessionInfo_Add(outClientSession->parentSession, name);
|
||||
outClientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&outClientSession->syncObject.autoObject);
|
||||
}
|
||||
}
|
||||
@@ -163,7 +157,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x4010042:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:pm") == 0)
|
||||
if(info != NULL && kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
|
||||
{
|
||||
res = doPublishToProcessHook(handle, cmdbuf);
|
||||
skip = true;
|
||||
@@ -176,7 +170,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk4
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -185,7 +179,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk8
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -194,7 +188,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk4
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -203,7 +197,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "cfg:i") == 0) // GetConfigInfoBlk8
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -212,7 +206,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); // SecureInfoGetRegion
|
||||
if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0))
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -221,7 +215,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); // SecureInfoGetRegion
|
||||
if(info != NULL && strcmp(info->name, "cfg:i") == 0)
|
||||
skip = doLangEmu(&res, handle, cmdbuf);
|
||||
skip = doLangEmu(&res, cmdbuf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -26,10 +26,12 @@
|
||||
|
||||
#include "svc/SetWifiEnabled.h"
|
||||
|
||||
void SetWifiEnabled(bool enable)
|
||||
Result SetWifiEnabled(bool enable)
|
||||
{
|
||||
if(enable)
|
||||
CFG11_WIFICNT |= 1;
|
||||
else
|
||||
CFG11_WIFICNT &= ~1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -50,14 +50,7 @@ Result TranslateHandle(u32 *outKAddr, char *outClassName, Handle handle)
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7; // invalid handle
|
||||
|
||||
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
obj->vtable->GetClassToken(&tok, obj);
|
||||
name = tok.name;
|
||||
}
|
||||
else
|
||||
name = obj->vtable->GetClassName(obj);
|
||||
name = classNameOfAutoObject(obj);
|
||||
|
||||
if(name == NULL) // shouldn't happen
|
||||
name = "KAutoObject";
|
||||
@@ -24,10 +24,14 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "globals.h"
|
||||
#include "svc/MapProcessMemoryEx.h"
|
||||
|
||||
Result UnmapProcessMemoryEx(Handle processHandle UNUSED, void *dst, u32 size)
|
||||
Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size)
|
||||
{
|
||||
if(kernelVersion < SYSTEM_VERSION(2, 37, 0)) // < 6.x
|
||||
return UnmapProcessMemory(processHandle, dst, size); // equivalent when size <= 64MB
|
||||
|
||||
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
|
||||
Result res = KProcessHwInfo__UnmapProcessMemory(currentHwInfo, dst, size >> 12);
|
||||
@@ -37,6 +37,7 @@
|
||||
pop {r1, r2, r12, pc}
|
||||
.endm
|
||||
|
||||
GEN_GETINFO_WRAPPER Handle
|
||||
GEN_GETINFO_WRAPPER System
|
||||
GEN_GETINFO_WRAPPER Process
|
||||
GEN_GETINFO_WRAPPER Thread
|
||||
@@ -113,9 +113,7 @@ svcHandler:
|
||||
push {r0-r7, r12, lr}
|
||||
|
||||
push {r0-r3}
|
||||
ldr r0, =PostprocessSvc
|
||||
ldr r0, [r0]
|
||||
blx r0
|
||||
bl postprocessSvc
|
||||
pop {r0-r3}
|
||||
|
||||
ldrb lr, [sp, #0x58+0] @ page end - 0xb8 + 0: scheduling flags
|
||||
160
k11_extension/source/synchronization.c
Normal file
160
k11_extension/source/synchronization.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 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 and 7.c of GPLv3 apply 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.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "synchronization.h"
|
||||
#include "utils.h"
|
||||
#include "kernel.h"
|
||||
#include "globals.h"
|
||||
|
||||
extern SGI0Handler_t SGI0Handler;
|
||||
|
||||
void executeFunctionOnCores(SGI0Handler_t handler, u8 targetList, u8 targetListFilter)
|
||||
{
|
||||
u32 coreID = getCurrentCoreID();
|
||||
SGI0Handler = handler;
|
||||
|
||||
if(targetListFilter == 0 && (targetListFilter & (1 << coreID)) != 0)
|
||||
__enable_irq(); // make sure interrupts aren't masked
|
||||
MPCORE_GID_SGI = (targetListFilter << 24) | (targetList << 16) | 0;
|
||||
}
|
||||
|
||||
void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this)
|
||||
{
|
||||
this->triggerCrossCoreInterrupt = false;
|
||||
for(s16 i = 0; i < (s16)getNumberOfCores(); i++)
|
||||
{
|
||||
if(this->coreNumber != i)
|
||||
MPCORE_GID_SGI = (1 << (16 + i)) | 8;
|
||||
}
|
||||
}
|
||||
|
||||
void KThread__DebugReschedule(KThread *this, bool lock)
|
||||
{
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
|
||||
u32 oldSchedulingMask = this->schedulingMask;
|
||||
if(lock) // the original k11 function discards the other flags
|
||||
this->schedulingMask |= 0x80;
|
||||
else
|
||||
this->schedulingMask &= ~0x80;
|
||||
|
||||
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, this, oldSchedulingMask);
|
||||
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
}
|
||||
|
||||
bool rosalinaThreadLockPredicate(KThread *thread)
|
||||
{
|
||||
KProcess *process = thread->ownerProcess;
|
||||
if(process == NULL)
|
||||
return false;
|
||||
|
||||
u64 titleId = codeSetOfProcess(process)->titleId;
|
||||
u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)titleId;
|
||||
return
|
||||
((rosalinaState & 1) && idOfProcess(process) >= nbSection0Modules &&
|
||||
(highTitleId != 0x00040130 || (highTitleId == 0x00040130 && (lowTitleId == 0x1A02 || lowTitleId == 0x1C02))));
|
||||
}
|
||||
|
||||
void rosalinaRescheduleThread(KThread *thread, bool lock)
|
||||
{
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
|
||||
u32 oldSchedulingMask = thread->schedulingMask;
|
||||
if(lock)
|
||||
thread->schedulingMask |= 0x40;
|
||||
else
|
||||
thread->schedulingMask &= ~0x40;
|
||||
|
||||
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
|
||||
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
}
|
||||
|
||||
void rosalinaLockThread(KThread *thread)
|
||||
{
|
||||
KThread *syncThread = synchronizationMutex->owner;
|
||||
|
||||
if(syncThread == NULL || syncThread != thread)
|
||||
rosalinaRescheduleThread(thread, true);
|
||||
}
|
||||
|
||||
void rosalinaLockAllThreads(void)
|
||||
{
|
||||
bool currentThreadsFound = false;
|
||||
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
if(!rosalinaThreadLockPredicate(thread))
|
||||
continue;
|
||||
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
|
||||
currentThreadsFound = true;
|
||||
else
|
||||
rosalinaLockThread(thread);
|
||||
}
|
||||
|
||||
if(currentThreadsFound)
|
||||
{
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
if(!rosalinaThreadLockPredicate(thread))
|
||||
continue;
|
||||
if(!(thread->schedulingMask & 0x40))
|
||||
{
|
||||
rosalinaLockThread(thread);
|
||||
KRecursiveLock__Lock(criticalSectionLock);
|
||||
if(thread->coreId != getCurrentCoreID())
|
||||
{
|
||||
u32 cpsr = __get_cpsr();
|
||||
__disable_irq();
|
||||
coreCtxs[thread->coreId].objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
|
||||
currentCoreContext->objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
|
||||
__set_cpsr_cx(cpsr);
|
||||
}
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
}
|
||||
}
|
||||
KScheduler__TriggerCrossCoreInterrupt(currentCoreContext->objectContext.currentScheduler);
|
||||
}
|
||||
KRecursiveLock__Unlock(criticalSectionLock);
|
||||
}
|
||||
|
||||
void rosalinaUnlockAllThreads(void)
|
||||
{
|
||||
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
|
||||
{
|
||||
KThread *thread = (KThread *)node->key;
|
||||
|
||||
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
|
||||
continue;
|
||||
|
||||
if(thread->schedulingMask & 0x40)
|
||||
rosalinaRescheduleThread(thread, false);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/k11MainHook.bin", 0
|
||||
.arm
|
||||
|
||||
bindSGI0:
|
||||
; hook __kernel_main to bind SGI0 for own purposes
|
||||
push {r0-r4, lr}
|
||||
sub sp, #16 ; 3 args passed through the stack + alignment
|
||||
ldr r0, [interruptManager]
|
||||
adr r1, interruptEvent
|
||||
mov r2, #0
|
||||
mrc p15, 0, r3, c0, c0, 5
|
||||
and r3, #3
|
||||
mov r4, #0
|
||||
str r4, [sp]
|
||||
str r4, [sp, #4]
|
||||
str r4, [sp, #8]
|
||||
|
||||
ldr r12, [InterruptManager_mapInterrupt]
|
||||
blx r12
|
||||
cmp r0, #0
|
||||
blt .
|
||||
|
||||
add sp, #16
|
||||
pop {r0-r4, pc}
|
||||
|
||||
executeCustomHandler:
|
||||
push {r4, lr}
|
||||
mrs r4, cpsr
|
||||
adr r0, customHandler
|
||||
bl convertVAToPA
|
||||
orr r0, #(1 << 31)
|
||||
ldr r12, [r0]
|
||||
|
||||
blx r12
|
||||
|
||||
mov r0, #0
|
||||
msr cpsr_cx, r4
|
||||
pop {r4, pc}
|
||||
|
||||
convertVAToPA:
|
||||
mov r1, #0x1000
|
||||
sub r1, #1
|
||||
and r2, r0, r1
|
||||
bic r0, r1
|
||||
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
|
||||
tst r0, #1 ; failure bit
|
||||
bic r0, r1
|
||||
addeq r0, r2
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
; Result InterruptManager::mapInterrupt(InterruptManager *this, InterruptEvent *iEvent, u32 interruptID, u32 coreID, s32 priority, bool willBeMasked, bool isLevelHighActive);
|
||||
InterruptManager_mapInterrupt: .ascii "bind"
|
||||
|
||||
_vtable: .word executeCustomHandler
|
||||
interruptEvent: .word _vtable
|
||||
|
||||
parameters:
|
||||
customHandler: .ascii "hdlr"
|
||||
interruptManager: .word 0
|
||||
L2MMUTable: .word 0
|
||||
funcs: .word 0,0,0
|
||||
TTBCR: .word 0
|
||||
L1MMUTableAddrs: .word 0,0,0,0
|
||||
kernelVersion: .word 0
|
||||
CFWInfo: .word 0,0,0,0
|
||||
|
||||
.close
|
||||
@@ -1,36 +0,0 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/mmuHook.bin", 0
|
||||
.arm
|
||||
; r2 = L1 table
|
||||
; Thanks @Dazzozo for giving me that idea
|
||||
; Maps physmem so that, if addr is in physmem(0, 0x30000000), it can be accessed uncached&rwx as addr|(1<<31)
|
||||
; Save the value of all registers
|
||||
|
||||
push {r0-r1, r3-r7}
|
||||
mov r0, #0
|
||||
mov r1, #0x30000000 ; end address
|
||||
ldr r3, =#0x40C02 ; supersection (rwx for all) of strongly ordered memory, shared
|
||||
loop:
|
||||
orr r4, r0, #0x80000000
|
||||
orr r5, r0, r3
|
||||
|
||||
mov r6, #0 ;
|
||||
loop2:
|
||||
add r7, r6, r4,lsr #20
|
||||
str r5, [r2, r7,lsl #2]
|
||||
add r6, #1
|
||||
cmp r6, #16
|
||||
blo loop2
|
||||
|
||||
add r0, #0x01000000
|
||||
cmp r0, r1
|
||||
blo loop
|
||||
pop {r0-r1, r3-r7}
|
||||
|
||||
mov r3, #0xe0000000 ; instruction that has been patched
|
||||
bx lr
|
||||
|
||||
|
||||
.pool
|
||||
.close
|
||||
@@ -64,7 +64,7 @@ firm_maxsize equ 0x07FFF000
|
||||
; Copy argv[0]
|
||||
ldr r0, =fname_addr
|
||||
adr r1, fname
|
||||
mov r2, #42
|
||||
mov r2, #82
|
||||
bl memcpy16
|
||||
|
||||
ldr r0, =argv_addr
|
||||
@@ -153,7 +153,7 @@ fname: .ascii "FILE"
|
||||
movne r2, r8
|
||||
blne memcpy32
|
||||
add r5, #1
|
||||
cmp r5, #3
|
||||
cmp r5, #4
|
||||
blo load_section_loop
|
||||
|
||||
mov r0, #2 ; argc
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/svcConnectToPortInitHook.bin", 0
|
||||
.arm
|
||||
push {r0-r4, lr}
|
||||
adr r0, jumpAddress
|
||||
bl convertVAToPA
|
||||
orr r4, r0, #(1 << 31)
|
||||
|
||||
loop:
|
||||
ldr r12, [r4]
|
||||
cmp r12, #0
|
||||
bne loop_end
|
||||
ldr r12, [SleepThread]
|
||||
ldr r0, =(10 * 1000 * 1000)
|
||||
mov r1, #0
|
||||
blx r12
|
||||
b loop
|
||||
|
||||
loop_end:
|
||||
pop {r0-r4, lr}
|
||||
bx r12
|
||||
|
||||
convertVAToPA:
|
||||
mov r1, #0x1000
|
||||
sub r1, #1
|
||||
and r2, r0, r1
|
||||
bic r0, r1
|
||||
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
|
||||
tst r0, #1 ; failure bit
|
||||
bic r0, r1
|
||||
addeq r0, r2
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
_base: .ascii "base"
|
||||
jumpAddressOrig: .ascii "orig"
|
||||
SleepThread: .ascii "SlpT"
|
||||
jumpAddress: .word 0
|
||||
|
||||
.close
|
||||
@@ -1,20 +0,0 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/svcCustomBackdoor.bin", 0
|
||||
.arm
|
||||
|
||||
; Result svcCustomBackdoor(void *func, ... <up to 3 args>)
|
||||
svcCustomBackdoor:
|
||||
b skip_orig
|
||||
orig: .word 0
|
||||
skip_orig:
|
||||
push {r4, lr}
|
||||
mov r4, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
blx r4
|
||||
pop {r4, pc}
|
||||
|
||||
.pool
|
||||
.close
|
||||
@@ -45,7 +45,8 @@
|
||||
|
||||
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
||||
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
|
||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT)
|
||||
#define NTRBOOT_BUTTONS (BUTTON_START | BUTTON_SELECT | BUTTON_X)
|
||||
|
||||
237
source/config.c
237
source/config.c
@@ -35,7 +35,7 @@
|
||||
|
||||
CfgData configData;
|
||||
ConfigurationStatus needConfig;
|
||||
static u32 oldConfig;
|
||||
static CfgData oldConfig;
|
||||
|
||||
bool readConfig(void)
|
||||
{
|
||||
@@ -46,30 +46,30 @@ bool readConfig(void)
|
||||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
|
||||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
||||
{
|
||||
configData.config = 0;
|
||||
memset(&configData, 0, sizeof(CfgData));
|
||||
|
||||
ret = false;
|
||||
}
|
||||
else ret = true;
|
||||
|
||||
oldConfig = configData.config;
|
||||
oldConfig = configData;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void writeConfig(bool isPayloadLaunch)
|
||||
void writeConfig(bool isConfigOptions)
|
||||
{
|
||||
if(isPayloadLaunch) configData.config = (configData.config & 0xFFFFFF80) | (oldConfig & 0x7F);
|
||||
|
||||
/* If the configuration is different from previously, overwrite it.
|
||||
Just the no-forcing flag being set is not enough */
|
||||
if(needConfig != CREATE_CONFIGURATION && (configData.config & 0xFFFFFFBF) == oldConfig) return;
|
||||
//If the configuration is different from previously, overwrite it.
|
||||
if(needConfig != CREATE_CONFIGURATION && ((isConfigOptions && configData.config == oldConfig.config && configData.multiConfig == oldConfig.multiConfig) ||
|
||||
(!isConfigOptions && configData.bootConfig == oldConfig.bootConfig))) return;
|
||||
|
||||
if(needConfig == CREATE_CONFIGURATION)
|
||||
{
|
||||
memcpy(configData.magic, "CONF", 4);
|
||||
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
|
||||
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
|
||||
|
||||
needConfig = MODIFY_CONFIGURATION;
|
||||
}
|
||||
|
||||
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
||||
@@ -78,115 +78,116 @@ void writeConfig(bool isPayloadLaunch)
|
||||
|
||||
void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
{
|
||||
const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
||||
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||
"Splash: Off( ) Before( ) After( ) payloads",
|
||||
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
||||
};
|
||||
static const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
||||
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||
"Splash: Off( ) Before( ) After( ) payloads",
|
||||
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
||||
};
|
||||
|
||||
const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
|
||||
"( ) Use EmuNAND FIRM if booting with R",
|
||||
"( ) Enable loading external FIRMs and modules",
|
||||
"( ) Enable game patching",
|
||||
"( ) Show NAND or user string in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
"( ) Patch ARM9 access",
|
||||
"( ) Set developer UNITINFO",
|
||||
};
|
||||
static const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
|
||||
"( ) Use EmuNAND FIRM if booting with R",
|
||||
"( ) Enable loading external FIRMs and modules",
|
||||
"( ) Enable game patching",
|
||||
"( ) Show NAND or user string in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
"( ) Set developer UNITINFO",
|
||||
"( ) Disable ARM11 exception handlers",
|
||||
};
|
||||
|
||||
const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||
"It will be booted when no\n"
|
||||
"directional pad buttons are pressed.",
|
||||
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||
"It will be booted when no\n"
|
||||
"directional pad buttons are pressed.",
|
||||
|
||||
"Select the screen brightness.",
|
||||
"Select the screen brightness.",
|
||||
|
||||
"Enable splash screen support.\n\n"
|
||||
"\t* 'Before payloads' displays it\n"
|
||||
"before booting payloads\n"
|
||||
"(intended for splashes that display\n"
|
||||
"button hints).\n\n"
|
||||
"\t* 'After payloads' displays it\n"
|
||||
"afterwards.",
|
||||
"Enable splash screen support.\n\n"
|
||||
"\t* 'Before payloads' displays it\n"
|
||||
"before booting payloads\n"
|
||||
"(intended for splashes that display\n"
|
||||
"button hints).\n\n"
|
||||
"\t* 'After payloads' displays it\n"
|
||||
"afterwards.",
|
||||
|
||||
"Activate a PIN lock.\n\n"
|
||||
"The PIN will be asked each time\n"
|
||||
"Luma3DS boots.\n\n"
|
||||
"4, 6 or 8 digits can be selected.\n\n"
|
||||
"The ABXY buttons and the directional\n"
|
||||
"pad buttons can be used as keys.\n\n"
|
||||
"A message can also be displayed\n"
|
||||
"(refer to the wiki for instructions).",
|
||||
"Activate a PIN lock.\n\n"
|
||||
"The PIN will be asked each time\n"
|
||||
"Luma3DS boots.\n\n"
|
||||
"4, 6 or 8 digits can be selected.\n\n"
|
||||
"The ABXY buttons and the directional\n"
|
||||
"pad buttons can be used as keys.\n\n"
|
||||
"A message can also be displayed\n"
|
||||
"(refer to the wiki for instructions).",
|
||||
|
||||
"Select the New 3DS CPU mode.\n\n"
|
||||
"This won't apply to\n"
|
||||
"New 3DS exclusive/enhanced games.\n\n"
|
||||
"'Clock+L2' can cause issues with some\n"
|
||||
"games.",
|
||||
"Select the New 3DS CPU mode.\n\n"
|
||||
"This won't apply to\n"
|
||||
"New 3DS exclusive/enhanced games.\n\n"
|
||||
"'Clock+L2' can cause issues with some\n"
|
||||
"games.",
|
||||
|
||||
"If enabled, an EmuNAND\n"
|
||||
"will be launched on boot.\n\n"
|
||||
"Otherwise, SysNAND will.\n\n"
|
||||
"Hold L on boot to switch NAND.\n\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, an EmuNAND\n"
|
||||
"will be launched on boot.\n\n"
|
||||
"Otherwise, SysNAND will.\n\n"
|
||||
"Hold L on boot to switch NAND.\n\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"
|
||||
"SysNAND will be booted with an\n"
|
||||
"EmuNAND FIRM.\n\n"
|
||||
"Otherwise, an EmuNAND will be booted\n"
|
||||
"with the SysNAND FIRM.\n\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), also add A if you have\n"
|
||||
"a matching payload.",
|
||||
"If enabled, when holding R on boot\n"
|
||||
"SysNAND will be booted with an\n"
|
||||
"EmuNAND FIRM.\n\n"
|
||||
"Otherwise, an EmuNAND will be booted\n"
|
||||
"with the SysNAND FIRM.\n\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), also add A if you have\n"
|
||||
"a matching payload.",
|
||||
|
||||
"Enable loading external FIRMs and\n"
|
||||
"system modules.\n\n"
|
||||
"This isn't needed in most cases.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
"Enable loading external FIRMs and\n"
|
||||
"system modules.\n\n"
|
||||
"This isn't needed in most cases.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable overriding the region and\n"
|
||||
"language configuration and the usage\n"
|
||||
"of patched code binaries,\n"
|
||||
"IPS code patches and LayeredFS\n"
|
||||
"for specific games.\n\n"
|
||||
"Also makes certain DLCs\n"
|
||||
"for out-of-region games work.\n\n"
|
||||
"Enabling this requires the\n"
|
||||
"archive patch to be applied.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
"Enable overriding the region and\n"
|
||||
"language configuration and the usage\n"
|
||||
"of patched code binaries, exHeaders,\n"
|
||||
"IPS code patches and LayeredFS\n"
|
||||
"for specific games.\n\n"
|
||||
"Also makes certain DLCs\n"
|
||||
"for out-of-region games work.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable showing the current NAND/FIRM:\n\n"
|
||||
"\t* Sys = SysNAND\n"
|
||||
"\t* Emu = EmuNAND 1\n"
|
||||
"\t* EmuX = EmuNAND X\n"
|
||||
"\t* SysE = SysNAND with EmuNAND 1 FIRM\n"
|
||||
"\t* SyEX = SysNAND with EmuNAND X FIRM\n"
|
||||
"\t* EmuS = EmuNAND 1 with SysNAND FIRM\n"
|
||||
"\t* EmXS = EmuNAND X with SysNAND FIRM\n\n"
|
||||
"or a user-defined custom string in\n"
|
||||
"System Settings.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
"Enable showing the current NAND/FIRM:\n\n"
|
||||
"\t* Sys = SysNAND\n"
|
||||
"\t* Emu = EmuNAND 1\n"
|
||||
"\t* EmuX = EmuNAND X\n"
|
||||
"\t* SysE = SysNAND with EmuNAND 1 FIRM\n"
|
||||
"\t* SyEX = SysNAND with EmuNAND X FIRM\n"
|
||||
"\t* EmuS = EmuNAND 1 with SysNAND FIRM\n"
|
||||
"\t* EmXS = EmuNAND X with SysNAND FIRM\n\n"
|
||||
"or a user-defined custom string in\n"
|
||||
"System Settings.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable showing the GBA boot screen\n"
|
||||
"when booting GBA games.",
|
||||
"Enable showing the GBA boot screen\n"
|
||||
"when booting GBA games.",
|
||||
|
||||
"Disable ARM9 exheader access checks.\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
"Make the console be always detected\n"
|
||||
"as a development unit, and conversely.\n"
|
||||
"(which breaks online features, amiibo\n"
|
||||
"and retail CIAs, but allows installing\n"
|
||||
"and booting some developer software).\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
|
||||
"Make the console be always detected\n"
|
||||
"as a development unit, and conversely.\n"
|
||||
"(which breaks online features, amiibo\n"
|
||||
"and retail CIAs, but allows installing\n"
|
||||
"and booting some developer software).\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
};
|
||||
"Disables the fatal error exception\n"
|
||||
"handlers for the ARM11 CPU.\n\n"
|
||||
"Note: Disabling the exception handlers\n"
|
||||
"will disqualify you from submitting\n"
|
||||
"issues or bug reports to the Luma3DS\n"
|
||||
"GitHub repository!"
|
||||
};
|
||||
|
||||
struct multiOption {
|
||||
u32 posXs[4];
|
||||
@@ -232,8 +233,14 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
|
||||
initScreens();
|
||||
|
||||
static const char *bootTypes[] = { "B9S",
|
||||
"B9S (ntrboot)",
|
||||
"FIRM0",
|
||||
"FIRM1" };
|
||||
|
||||
drawString(true, 10, 10, COLOR_TITLE, CONFIG_TITLE);
|
||||
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to save");
|
||||
drawFormattedString(false, 10, SCREEN_HEIGHT - 2 * SPACING_Y, COLOR_YELLOW, "Booted from %s via %s", isSdMode ? "SD" : "CTRNAND", bootTypes[(u32)bootType]);
|
||||
|
||||
//Character to display a selected option
|
||||
char selected = 'x';
|
||||
@@ -277,9 +284,9 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput(true);
|
||||
pressed = waitInput(true) & MENU_BUTTONS;
|
||||
}
|
||||
while(!(pressed & MENU_BUTTONS));
|
||||
while(!pressed);
|
||||
|
||||
if(pressed == BUTTON_START) break;
|
||||
|
||||
@@ -373,19 +380,25 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
else if(singleOptions[singleSelected].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED, selected);
|
||||
}
|
||||
|
||||
//Preserve the last-used boot options (first 9 bits)
|
||||
configData.config &= 0x7F;
|
||||
|
||||
//Parse and write the new configuration
|
||||
configData.multiConfig = 0;
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
configData.config |= multiOptions[i].enabled << (i * 2 + 7);
|
||||
configData.multiConfig |= multiOptions[i].enabled << (i * 2);
|
||||
|
||||
configData.config = 0;
|
||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 17);
|
||||
configData.config |= (singleOptions[i].enabled ? 1 : 0) << i;
|
||||
|
||||
writeConfig(true);
|
||||
|
||||
u32 newPinMode = MULTICONFIG(PIN);
|
||||
|
||||
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
|
||||
else if(oldPinStatus) fileDelete(PIN_FILE);
|
||||
else if(oldPinStatus)
|
||||
{
|
||||
if(!fileDelete(PIN_FILE))
|
||||
error("Unable to delete PIN file");
|
||||
}
|
||||
|
||||
while(HID_PAD & PIN_BUTTONS);
|
||||
wait(2000ULL);
|
||||
|
||||
@@ -28,17 +28,18 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define CONFIG(a) (((configData.config >> (a + 17)) & 1) != 0)
|
||||
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 7)) & 3)
|
||||
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
|
||||
#define CONFIG(a) (((configData.config >> (a)) & 1) != 0)
|
||||
#define MULTICONFIG(a) ((configData.multiConfig >> (2 * (a))) & 3)
|
||||
#define BOOTCONFIG(a, b) ((configData.bootConfig >> (a)) & (b))
|
||||
|
||||
#define CONFIG_FILE "config.bin"
|
||||
#define CONFIG_VERSIONMAJOR 1
|
||||
#define CONFIG_VERSIONMINOR 12
|
||||
#define CONFIG_VERSIONMAJOR 2
|
||||
#define CONFIG_VERSIONMINOR 2
|
||||
|
||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
|
||||
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
|
||||
|
||||
enum multiOptions
|
||||
{
|
||||
@@ -57,8 +58,8 @@ enum singleOptions
|
||||
PATCHGAMES,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHACCESS,
|
||||
PATCHUNITINFO
|
||||
PATCHUNITINFO,
|
||||
DISABLEARM11EXCHANDLERS
|
||||
};
|
||||
|
||||
typedef enum ConfigurationStatus
|
||||
@@ -68,6 +69,8 @@ typedef enum ConfigurationStatus
|
||||
CREATE_CONFIGURATION
|
||||
} ConfigurationStatus;
|
||||
|
||||
extern CfgData configData;
|
||||
|
||||
bool readConfig(void);
|
||||
void writeConfig(bool isPayloadLaunch);
|
||||
void writeConfig(bool isConfigOptions);
|
||||
void configMenu(bool oldPinStatus, u32 oldPinMode);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "crypto.h"
|
||||
#include "memory.h"
|
||||
#include "emunand.h"
|
||||
#include "strings.h"
|
||||
#include "utils.h"
|
||||
#include "fatfs/sdmmc/sdmmc.h"
|
||||
@@ -326,7 +327,7 @@ __attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE];
|
||||
static u8 nandSlot;
|
||||
static u32 fatStart = 0;
|
||||
|
||||
FirmwareSource firmSource;
|
||||
FirmwareSource firmSource = FIRMWARE_SYSNAND;
|
||||
|
||||
__attribute__((aligned(4))) static const u8 key1s[2][AES_BLOCK_SIZE] = {
|
||||
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
|
||||
@@ -421,12 +422,17 @@ int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool decryptExeFs(Cxi *cxi)
|
||||
u32 decryptExeFs(Cxi *cxi)
|
||||
{
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false;
|
||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return 0;
|
||||
|
||||
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
||||
if(cxi->ncch.exeFsOffset != 5) return 0;
|
||||
|
||||
u8 *exeFsOffset = (u8 *)cxi + 6 * 0x200;
|
||||
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
||||
|
||||
if(exeFsSize > 0x400000) return 0;
|
||||
|
||||
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
@@ -438,14 +444,14 @@ bool decryptExeFs(Cxi *cxi)
|
||||
aes_use_keyslot(0x2C);
|
||||
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
return memcmp(cxi, "FIRM", 4) == 0;
|
||||
return memcmp(cxi, "FIRM", 4) == 0 ? exeFsSize : 0;
|
||||
}
|
||||
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
||||
u32 decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
|
||||
{
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false;
|
||||
if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return 0;
|
||||
|
||||
__attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
|
||||
__attribute__((aligned(4))) static const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
|
||||
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
|
||||
cetkIv[AES_BLOCK_SIZE] = {0};
|
||||
memcpy(titleKey, ticket->titleKey, sizeof(titleKey));
|
||||
@@ -484,8 +490,8 @@ static inline void twlConsoleInfoInit(void)
|
||||
aes_setkey(2, (u8 *)0x01FFD398, AES_KEYX, AES_INPUT_TWLNORMAL);
|
||||
if(CFG_TWLUNITINFO != 0)
|
||||
{
|
||||
__attribute__((aligned(4))) u8 key2YDev[AES_BLOCK_SIZE] = {0x3B, 0x06, 0x86, 0x57, 0x33, 0x04, 0x88, 0x11, 0x49, 0x04, 0x6B, 0x33, 0x12, 0x02, 0xAC, 0xF3},
|
||||
key3YDev[AES_BLOCK_SIZE] = {0xAA, 0xBF, 0x76, 0xF1, 0x7A, 0xB8, 0xE8, 0x66, 0x97, 0x64, 0x6A, 0x26, 0x05, 0x00, 0xA0, 0xE1};
|
||||
__attribute__((aligned(4))) static const u8 key2YDev[AES_BLOCK_SIZE] = {0x3B, 0x06, 0x86, 0x57, 0x33, 0x04, 0x88, 0x11, 0x49, 0x04, 0x6B, 0x33, 0x12, 0x02, 0xAC, 0xF3},
|
||||
key3YDev[AES_BLOCK_SIZE] = {0xAA, 0xBF, 0x76, 0xF1, 0x7A, 0xB8, 0xE8, 0x66, 0x97, 0x64, 0x6A, 0x26, 0x05, 0x00, 0xA0, 0xE1};
|
||||
|
||||
k3X[1] = 0xEE7A4B1E;
|
||||
k3X[2] = 0xAF42C08B;
|
||||
@@ -510,15 +516,15 @@ static inline void twlConsoleInfoInit(void)
|
||||
void setupKeyslots(void)
|
||||
{
|
||||
//Setup 0x24 KeyY
|
||||
__attribute__((aligned(4))) u8 keyY0x24[AES_BLOCK_SIZE] = {0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62};
|
||||
__attribute__((aligned(4))) static const u8 keyY0x24[AES_BLOCK_SIZE] = {0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62};
|
||||
aes_setkey(0x24, keyY0x24, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Setup 0x25 KeyX and 0x2F KeyY
|
||||
__attribute__((aligned(4))) const u8 keyX0x25s[2][AES_BLOCK_SIZE] = {
|
||||
__attribute__((aligned(4))) static const u8 keyX0x25s[2][AES_BLOCK_SIZE] = {
|
||||
{0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3},
|
||||
{0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B}
|
||||
},
|
||||
keyY0x2Fs[2][AES_BLOCK_SIZE] = {
|
||||
keyY0x2Fs[2][AES_BLOCK_SIZE] = {
|
||||
{0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16},
|
||||
{0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC}
|
||||
};
|
||||
@@ -529,7 +535,7 @@ void setupKeyslots(void)
|
||||
if(ISN3DS)
|
||||
{
|
||||
//Setup 0x05 KeyY
|
||||
__attribute__((aligned(4))) u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||
__attribute__((aligned(4))) static const u8 keyY0x5[AES_BLOCK_SIZE] = {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);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +110,6 @@
|
||||
#define SHA_224_HASH_SIZE (224 / 8)
|
||||
#define SHA_1_HASH_SIZE (160 / 8)
|
||||
|
||||
extern u32 emuOffset,
|
||||
emuHeader;
|
||||
extern FirmwareSource firmSource;
|
||||
|
||||
void sha(void *res, const void *src, u32 size, u32 mode);
|
||||
@@ -119,8 +117,8 @@ void sha(void *res, const void *src, u32 size, u32 mode);
|
||||
int ctrNandInit(void);
|
||||
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
||||
bool decryptExeFs(Cxi *cxi);
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
u32 decryptExeFs(Cxi *cxi);
|
||||
u32 decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
void setupKeyslots(void);
|
||||
void kernel9Loader(Arm9Bin *arm9Section);
|
||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
|
||||
bool loadSplash(void)
|
||||
{
|
||||
const char *topSplashFile = "splash.bin",
|
||||
*bottomSplashFile = "splashbottom.bin";
|
||||
static const char *topSplashFile = "splash.bin",
|
||||
*bottomSplashFile = "splashbottom.bin";
|
||||
|
||||
bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE,
|
||||
isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE;
|
||||
@@ -49,7 +49,6 @@ bool loadSplash(void)
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
initScreens();
|
||||
clearScreens(true);
|
||||
|
||||
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
|
||||
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
* Code for locating the SDMMC struct by Normmatt
|
||||
*/
|
||||
|
||||
|
||||
#include "emunand.h"
|
||||
#include "memory.h"
|
||||
#include "utils.h"
|
||||
#include "fatfs/sdmmc/sdmmc.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
@@ -102,22 +104,41 @@ void locateEmuNand(FirmwareSource *nandType)
|
||||
|
||||
static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||
static const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||
|
||||
//Looking for the last free space before Process9
|
||||
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(*freeK9Space == NULL) return false;
|
||||
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunand_bin_size ||
|
||||
*(u32 *)(*freeK9Space + 0x455 + emunand_bin_size - 4) != 0xFFFFFFFF) return false;
|
||||
|
||||
*freeK9Space += 0x455;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline u32 getOldSdmmc(u32 *sdmmc, u32 firmVersion)
|
||||
{
|
||||
switch(firmVersion)
|
||||
{
|
||||
case 0x18:
|
||||
*sdmmc = 0x080D91D8;
|
||||
break;
|
||||
case 0x1D:
|
||||
case 0x1F:
|
||||
*sdmmc = 0x080D8CD0;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
||||
{
|
||||
//Look for struct code
|
||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||
static const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||
|
||||
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
@@ -131,7 +152,7 @@ static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
||||
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
||||
{
|
||||
//Look for read/write code
|
||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||
static const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||
|
||||
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
@@ -154,7 +175,7 @@ static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
||||
static inline u32 patchMpu(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for MPU pattern
|
||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||
static const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
@@ -166,7 +187,7 @@ static inline u32 patchMpu(u8 *pos, u32 size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address)
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion)
|
||||
{
|
||||
u8 *freeK9Space;
|
||||
|
||||
@@ -186,7 +207,7 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
|
||||
//Find and add the SDMMC struct
|
||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
||||
u32 sdmmc;
|
||||
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||
if(!ret) *posSdmmc = sdmmc;
|
||||
|
||||
//Add EmuNAND hooks
|
||||
|
||||
@@ -34,5 +34,8 @@
|
||||
|
||||
#define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1)))
|
||||
|
||||
extern u32 emuOffset,
|
||||
emuHeader;
|
||||
|
||||
void locateEmuNand(FirmwareSource *nandType);
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address);
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address, u32 firmVersion);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "draw.h"
|
||||
#include "utils.h"
|
||||
#include "fmt.h"
|
||||
#include "buttons.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
void installArm9Handlers(void)
|
||||
@@ -41,7 +42,7 @@ void installArm9Handlers(void)
|
||||
/* IRQHandler is at 0x08000000, but we won't handle it for some reasons
|
||||
svcHandler is at 0x08000010, but we won't handle svc either */
|
||||
|
||||
const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
||||
static const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -60,17 +61,27 @@ void detectAndProcessExceptionDumps(void)
|
||||
const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize;
|
||||
const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize;
|
||||
|
||||
const char *handledExceptionNames[] = {
|
||||
static const char *handledExceptionNames[] = {
|
||||
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
||||
};
|
||||
|
||||
const char *specialExceptions[] = {
|
||||
},
|
||||
*specialExceptions[] = {
|
||||
"kernel panic", "svcBreak"
|
||||
};
|
||||
|
||||
const char *registerNames[] = {
|
||||
},
|
||||
*registerNames[] = {
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
||||
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||
},
|
||||
*faultStatusNames[] = {
|
||||
"Alignment", "Instr.cache maintenance op.",
|
||||
"Ext.Abort on translation - Lv1", "Ext.Abort on translation - Lv2",
|
||||
"Translation - Section", "Translation - Page", "Access bit - Section", "Access bit - Page",
|
||||
"Domain - Section", "Domain - Page", "Permission - Section", "Permission - Page",
|
||||
"Precise External Abort", "Imprecise External Abort", "Debug event"
|
||||
};
|
||||
|
||||
static const u32 faultStatusValues[] = {
|
||||
0b1, 0b100, 0b1100, 0b1110, 0b101, 0b111, 0b11, 0b110, 0b1001, 0b1011, 0b1101,
|
||||
0b1111, 0b1000, 0b10110, 0b10
|
||||
};
|
||||
|
||||
initScreens();
|
||||
@@ -78,7 +89,7 @@ void detectAndProcessExceptionDumps(void)
|
||||
drawString(true, 10, 10, COLOR_RED, "An exception occurred");
|
||||
u32 posY;
|
||||
if(dumpHeader->processor == 11) posY = drawFormattedString(true, 10, 30, COLOR_WHITE, "Processor: ARM11 (core %u)", dumpHeader->core);
|
||||
else posY = drawString(true, 10, 30, COLOR_WHITE, "Processor: ARM9");
|
||||
else posY = drawString(true, 10, 30, COLOR_WHITE, "Processor: ARM9");
|
||||
|
||||
if(dumpHeader->type == 2)
|
||||
{
|
||||
@@ -100,11 +111,25 @@ void detectAndProcessExceptionDumps(void)
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
}
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
}
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||
if(dumpHeader->processor == 11 && dumpHeader->type >= 2)
|
||||
{
|
||||
u32 xfsr = (dumpHeader->type == 2 ? regs[18] : regs[17]) & 0xF;
|
||||
|
||||
for(u32 i = 0; i < 15; i++)
|
||||
if(xfsr == faultStatusValues[i])
|
||||
{
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Fault status: %s", faultStatusNames[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dumpHeader->additionalDataSize != 0)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE,
|
||||
"Current process: %.8s (%016llX)", (const char *)additionalData, *(vu64 *)(additionalData + 8));
|
||||
posY += SPACING_Y;
|
||||
@@ -113,10 +138,15 @@ void detectAndProcessExceptionDumps(void)
|
||||
{
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%-7s%08X", registerNames[i], regs[i]);
|
||||
|
||||
if(i != 16 || dumpHeader->processor != 9)
|
||||
if(i != 16)
|
||||
posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[i + 1]);
|
||||
else if(dumpHeader->processor == 11)
|
||||
posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[20]);
|
||||
}
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->type == 3)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%-7s%08X Access type: %s", "FAR", regs[19], regs[17] & (1u << 11) ? "Write" : "Read");
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
u32 mode = regs[16] & 0xF;
|
||||
@@ -133,6 +163,16 @@ void detectAndProcessExceptionDumps(void)
|
||||
drawFormattedString(false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE, "%02X", *stackDump);
|
||||
}
|
||||
|
||||
static const char *choiceMessage[] = {"Press A to save the crash dump", "Press any other button to shutdown"};
|
||||
|
||||
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, choiceMessage[0]);
|
||||
drawString(true, 10, posY + SPACING_Y + SPACING_Y , COLOR_WHITE, choiceMessage[1]);
|
||||
|
||||
if(waitInput(false) != BUTTON_A) goto exit;
|
||||
|
||||
drawString(true, 10, posY + SPACING_Y, COLOR_BLACK, choiceMessage[0]);
|
||||
drawString(true, 10, posY + SPACING_Y + SPACING_Y , COLOR_BLACK, choiceMessage[1]);
|
||||
|
||||
char folderPath[12],
|
||||
path[36],
|
||||
fileName[24];
|
||||
@@ -143,15 +183,16 @@ void detectAndProcessExceptionDumps(void)
|
||||
|
||||
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
||||
{
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find a dump in the following file:");
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, path) + SPACING_Y;
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find the dump in the following file:");
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%s:/luma/%s", isSdMode ? "SD" : "CTRNAND", path) + SPACING_Y;
|
||||
}
|
||||
else posY = drawString(true, 10, posY + SPACING_Y, COLOR_RED, "Error writing the dump file");
|
||||
|
||||
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
|
||||
|
||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||
|
||||
waitInput(false);
|
||||
|
||||
exit:
|
||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||
mcuPowerOff();
|
||||
}
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
#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))
|
||||
|
||||
void installArm9Handlers(void);
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset, u32 *dAbtHandler, u32 dAbtHandlerMemAddress);
|
||||
void detectAndProcessExceptionDumps(void);
|
||||
|
||||
@@ -286,3 +286,17 @@ R0.12c (March 04, 2017)
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.13 (May 21, 2017)
|
||||
|
||||
Changed heading character of configuration keywords "_" to "FF_".
|
||||
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FatFs Module Source Files R0.12c
|
||||
FatFs Module Source Files R0.13
|
||||
|
||||
|
||||
FILES
|
||||
@@ -11,11 +11,12 @@ FILES
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external modules.
|
||||
ffunicode.c Optional Unicode utility functions.
|
||||
ffsystem.c An example of optional O/S related 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 it does not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module written to
|
||||
storage device. You need to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ DSTATUS disk_initialize (
|
||||
|
||||
if(sdmmcInitResult == 4) sdmmcInitResult = sdmmc_sdcard_init();
|
||||
|
||||
return ((pdrv == SDCARD && !(sdmmcInitResult & 2)) ||
|
||||
(pdrv == CTRNAND && !(sdmmcInitResult & 1) && !ctrNandInit())) ? 0 : STA_NOINIT;
|
||||
return ((pdrv == SDCARD && !(sdmmcInitResult & 2)) ||
|
||||
(pdrv == CTRNAND && !(sdmmcInitResult & 1) && !ctrNandInit())) ? 0 : STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandRead(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandRead(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
return ((pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
return ((pdrv == SDCARD && (*(vu16 *)(SDMMC_BASE + REG_SDSTATUS0) & TMIO_STAT0_WRPROTECT) != 0 && !sdmmc_sdcard_writesectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -91,12 +91,11 @@ DRESULT disk_write (
|
||||
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;
|
||||
return cmd == CTRL_SYNC ? RES_OK : RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
2536
source/fatfs/ff.c
2536
source/fatfs/ff.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/ FatFs - Generic FAT Filesystem module R0.13 /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
@@ -15,11 +15,12 @@
|
||||
/ 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 68300 /* Revision ID */
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 87030 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -28,7 +29,7 @@ extern "C" {
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if _FATFS != _FFCONF
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
@@ -36,7 +37,7 @@ extern "C" {
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
@@ -48,20 +49,19 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||
#if _USE_LFN == 0
|
||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||
#endif
|
||||
#if FF_LFN_UNICODE && FF_USE_LFN /* Unicode (UTF-16) string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#define _INC_TCHAR
|
||||
#endif
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#define _INC_TCHAR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -69,8 +69,8 @@ typedef char TCHAR;
|
||||
|
||||
/* Type of file size variables */
|
||||
|
||||
#if _FS_EXFAT
|
||||
#if _USE_LFN == 0
|
||||
#if FF_FS_EXFAT
|
||||
#if !FF_USE_LFN
|
||||
#error LFN must be enabled when enable exFAT
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
@@ -80,36 +80,36 @@ typedef DWORD FSIZE_t;
|
||||
|
||||
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* File system type (0:N/A) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
BYTE fs_type; /* Filesystem type (0:N/A) */
|
||||
BYTE pdrv; /* 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 id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if _MAX_SS != _MIN_SS
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if _USE_LFN != 0
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if _FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#if FF_FS_REENTRANT
|
||||
FF_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if _FS_RPATH != 0
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if _FS_EXFAT
|
||||
#if FF_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) */
|
||||
@@ -122,52 +122,52 @@ typedef struct {
|
||||
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) */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (_FDID) */
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
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:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} _FDID;
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
_FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr 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[] */
|
||||
#if !FF_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
@@ -176,16 +176,16 @@ typedef struct {
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
_FDID obj; /* Object identifier */
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if _USE_LFN != 0
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if _USE_FIND
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
@@ -199,9 +199,9 @@ typedef struct {
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if _USE_LFN != 0
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[13]; /* Altenative file name */
|
||||
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
|
||||
TCHAR fname[FF_MAX_LFN + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[13]; /* File name */
|
||||
#endif
|
||||
@@ -230,7 +230,7 @@ typedef enum {
|
||||
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_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
@@ -268,6 +268,7 @@ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
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_setcp (WORD cp); /* Set current code page */
|
||||
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 */
|
||||
@@ -280,6 +281,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
@@ -292,26 +294,27 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !_FS_READONLY && !_FS_NORTC
|
||||
#if !FF_FS_READONLY && !FF_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 */
|
||||
/* LFN support functions */
|
||||
#if FF_USE_LFN /* Code conversion (defined in unicode.c) */
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (WCHAR uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
WCHAR ff_wtoupper (WCHAR uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
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 */
|
||||
#if FF_FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -358,4 +361,4 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FATFS */
|
||||
#endif /* FF_DEFINED */
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/ FatFs - Configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
#define FFCONF_DEF 87030 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_READONLY 0
|
||||
#define FF_FS_READONLY 0
|
||||
/* 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 0
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
@@ -25,43 +25,42 @@
|
||||
/ 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().
|
||||
#define FF_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
|
||||
#define FF_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
|
||||
#define FF_USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 0
|
||||
#define FF_USE_FASTSEEK 0
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_EXPAND 0
|
||||
#define FF_USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_CHMOD 0
|
||||
#define FF_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. */
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define _USE_LABEL 0
|
||||
#define FF_USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
#define FF_USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
@@ -69,11 +68,10 @@
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE 437
|
||||
#define FF_CODE_PAGE 437
|
||||
/* 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.
|
||||
/ Incorrect code page setting can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
@@ -95,47 +93,50 @@
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
/ 0 - Include all code pages above and configured by f_setcp()
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN 2
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN switches the support of long file name (LFN).
|
||||
#define FF_USE_LFN 2
|
||||
#define FF_MAX_LFN 255
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
||||
/ 0: Disable LFN. FF_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.
|
||||
/ to the project. The working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional 608 bytes at exFAT enabled. FF_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:UTF-16)
|
||||
/ 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 FF_LFN_UNICODE 0
|
||||
/* This option switches character encoding on the API, 0:ANSI/OEM or 1:UTF-16,
|
||||
/ when LFN is enabled. Also behavior of string I/O functions will be affected by
|
||||
/ this option. When LFN is not enabled, this option has no effect.
|
||||
*/
|
||||
|
||||
|
||||
#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().
|
||||
#define FF_STRF_ENCODE 3
|
||||
/* When FF_LFN_UNICODE = 1 with LFN enabled, string I/O functions, f_gets(),
|
||||
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
|
||||
/ This option selects assumption of character encoding ON THE FILE to be
|
||||
/ read/written via those functions.
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ This option has no effect when _LFN_UNICODE == 0. */
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
*/
|
||||
|
||||
|
||||
#define _FS_RPATH 1
|
||||
/* This option configures support of relative path.
|
||||
#define FF_FS_RPATH 1
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
@@ -147,45 +148,45 @@
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 2
|
||||
#define FF_VOLUMES 2
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","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
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||
/* FF_STR_VOLUME_ID switches string support for volume ID.
|
||||
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to FF_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.
|
||||
#define FF_MULTI_PARTITION 0
|
||||
/* This option switches support for multiple volumes on the 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
|
||||
/ When this function 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, generic memory card and
|
||||
#define FF_MIN_SS 512
|
||||
#define FF_MAX_SS 512
|
||||
/* This set of options configures the range of sector size to be supported. (512,
|
||||
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
|
||||
/ for variable sector size mode and disk_ioctl() function needs to implement
|
||||
/ GET_SECTOR_SIZE command. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
|
||||
#define FF_USE_TRIM 0
|
||||
/* This option switches support for 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
|
||||
#define FF_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.
|
||||
@@ -202,36 +203,36 @@
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 0
|
||||
#define FF_FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked FF_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. */
|
||||
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
#define FF_FS_EXFAT 0
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled.
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2017
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 5
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2017
|
||||
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_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). */
|
||||
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
|
||||
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (FF_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
|
||||
#define FF_FS_LOCK 0
|
||||
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
@@ -241,23 +242,23 @@
|
||||
/ 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
|
||||
#define FF_FS_REENTRANT 0
|
||||
#define FF_FS_TIMEOUT 1000
|
||||
#define FF_SYNC_t HANDLE
|
||||
/* The option FF_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.
|
||||
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_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*,
|
||||
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The FF_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.h. */
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user