Compare commits

...

118 Commits
v8.0 ... v8.1.1

Author SHA1 Message Date
Aurora Wright
f6483ec602 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-08-07 21:20:18 +02:00
Aurora Wright
36c1da1d61 Add mention of exheaders in the Enable game patching description 2017-08-07 21:20:08 +02:00
Stary 2001
6bcb1f8679 Merge pull request #763 from Streetwalrus/ir-title
Fix input redirection title index in the menu
2017-08-06 22:15:21 +01:00
Dan Elkouby
62932a9639 Fix input redirection title index in the menu
This option is the third, not the fourth, and toggling it will override
the "save settings" option's title instead.
2017-08-06 23:56:00 +03:00
Hikari-chin
a4629e4b65 Cleaned up and rearranged the Rosalina menu in preparation for future features 2017-08-01 17:38:48 +02:00
Aurora Wright
a0c2b43b34 Implement loading of exheaders from SD/CTRNAND (must be called luma/titles/TITLEID/exheader.bin), thanks to @HiddenRambler! 2017-08-01 17:38:23 +02:00
TuxSH
3907c46980 Follow ARM's documentation on hw watchpoints to the letter 2017-07-20 00:56:08 +02:00
TuxSH
7e7ab124a3 Log "logged" errdisp messages in /luma/errdisp.txt, fixes #707 2017-07-19 00:59:47 +02:00
TuxSH
cfc6cf24bf Some kext refactoring 2017-07-16 18:58:20 +02:00
TuxSH
46e9cb6b23 Fix fallthrough bug 2017-07-16 13:29:02 +02:00
TuxSH
ba14efe1f4 Suppress future -Wimplicit-fallthrough=3 warnings 2017-07-15 00:41:42 +02:00
TuxSH
3d8f62d38f Fix MaxCpuTime for 3dsx 2017-07-09 22:14:00 +02:00
Hikari-chin
3edaf0af64 Whoops 2017-07-09 14:36:06 -04:00
Aurora Wright
9273a88db7 It seems FB setup needs to be done first 2017-07-09 19:21:12 +02:00
Aurora Wright
37ba2c15de Reinstate framebuffer setup on initScreens to allow old Luma to be chainloaded if FB address changes in b9s/new Luma, remove useless clearScreens for the alternate FBs after the first init 2017-07-09 19:06:42 +02:00
Aurora Wright
557f2057f7 Fix spacing 2017-07-06 18:09:18 +02:00
Aurora Wright
6b5cc93780 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-07-06 17:29:43 +02:00
Aurora Wright
9760191af8 Fix conflict between emunand selection and payload booting when "Autoboot EmuNAND" is checked, you now need to press L + DPad to boot payloads if that option is checked 2017-07-06 17:29:38 +02:00
TuxSH
8845e4dd20 Merge pull request #704 from Hikari-chin/master
LED toggle switch in Rosalina's misc menu + updated README
2017-07-05 19:26:56 +02:00
Yuuki Hikari
8cf823f548 Update README.md 2017-07-05 02:13:03 -04:00
Hikari-chin
2538769f3a Added LED toggling from the Rosalina misc. menu 2017-07-04 23:50:40 -04:00
Aurora Wright
89fca38807 Merge master into local branch 2017-07-05 01:37:36 +02:00
Aurora Wright
dcc0eed69c Fix LayeredFS for games like Pokemon Art Academy which mistakenly use two forward slashes after the mountpoint 2017-07-05 01:31:04 +02:00
Yuuki Hikari
817475257e Merge pull request #700 from LiquidFenrir/wifi-toggle
Add wireless toggling in rosalina
2017-07-04 15:09:16 -04:00
LiquidFenrir
f2861058ba add wireless toggling in rosalina
https://github.com/AuroraWright/Luma3DS/issues/619#issuecomment-309239178

ligne 353: CFG11_WIFICNT, nothing includes it in rosalina so I hardcoded it here
ligne 363: could also use svc 0x5A (SetWifiEnabled) but not sure how
2017-07-04 18:35:55 +02:00
TuxSH
5d2a7315d5 Fix SetWifiEnabled 2017-07-03 19:28:34 +02:00
TuxSH
1520ab7555 Update ISSUE_TEMPLATE.md
7.1 => 8.1
2017-07-02 22:52:49 +02:00
Aurora Wright
d4d0fbd73b Re-add dir_build variable 2017-07-02 00:46:57 +02:00
Aurora Wright
ddb8e98e95 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-07-02 00:44:29 +02:00
Aurora Wright
fd69b4169f Use GNU/BSD agnostic syntax instead of detecting the OS (thanks @smartperson) 2017-07-02 00:44:14 +02:00
TuxSH
b48e0b5c5b Update ISSUE_TEMPLATE.md 2017-06-30 23:52:44 +02:00
TuxSH
31e2243c5c Update description for "enable game patching" 2017-06-28 21:59:57 +02:00
Aurora Wright
da0ee2e442 Fix external 3.x and 4.x FIRMs, fix 1.x and 2.x booting on dev units 2017-06-28 20:28:14 +02:00
Aurora Wright
b88dc9ac6a Only check in .text 2017-06-28 18:14:05 +02:00
Aurora Wright
9f78d7f62b Add region-free manuals patch 2017-06-28 17:37:12 +02:00
Aurora Wright
e67c6ed3ee Change pattern 2017-06-26 23:42:41 +02:00
Aurora Wright
2e111ca91b Revert "Revert "Merge pull request #662 from MerryMage/dsp-sig""
This reverts commit 62d51fd99d.
2017-06-26 23:39:28 +02:00
Aurora Wright
62d51fd99d Revert "Merge pull request #662 from MerryMage/dsp-sig"
This reverts commit a9289b1f21, reversing
changes made to d42e938232.
2017-06-26 22:06:10 +02:00
TuxSH
a9289b1f21 Merge pull request #662 from MerryMage/dsp-sig
Add a patch to disable DSP firmware signature check
2017-06-26 20:51:16 +02:00
Aurora Wright
d42e938232 Restore 7.1 max module size for NATIVE_FIRM 2017-06-26 19:03:57 +02:00
MerryMage
3d3dcb1f28 Add DSP signature check patch 2017-06-26 17:34:43 +01:00
Aurora Wright
82143212ce Remove the need for Homebrew and GNU tools on macOS 2017-06-26 18:32:33 +02:00
TuxSH
7246a2664e Move section0 to second quarter of VRAM 2017-06-26 17:41:40 +02:00
Aurora Wright
1291f2520a Fix derp 2017-06-26 17:11:00 +02:00
TuxSH
042ecf5343 Fix write-only hw watchpoint handling 2017-06-26 16:57:25 +02:00
Aurora Wright
6e54dcc24c Add macOS building support (you need to install coreutils and gnu-sed with homebrew) 2017-06-26 16:29:04 +02:00
TuxSH
91378ef3c1 Fix menu display bugs 2017-06-25 00:14:07 +02:00
Aurora Wright
0377cbd2b4 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-06-22 15:49:31 +02:00
Aurora Wright
786ecf4fe4 Remove some configbit math 2017-06-22 15:49:23 +02:00
TuxSH
0fbdee313f Merge branch 'master' of github.com:AuroraWright/Luma3DS 2017-06-20 21:24:52 +02:00
Aurora Wright
9b8e2b933d Add missing checks in getFreeK9Space 2017-06-20 19:56:34 +02:00
TuxSH
cc64ef9670 Take fb stride into account 2017-06-20 18:29:30 +02:00
TuxSH
31ff6a1da8 Clarify option 2017-06-20 17:39:11 +02:00
TuxSH
94532e9cea Halve the time necessary to take a screenshot 2017-06-20 16:14:36 +02:00
Aurora Wright
3f93bc5988 Support 3.x+ EmuNANDs and 3.x SysNANDs (partially), external FIRMs coming soonŧ 2017-06-19 18:13:59 +02:00
TuxSH
39ca23d609 Add qGetTLSAddr 2017-06-19 16:04:19 +02:00
TuxSH
47a9c1b576 Fix FS patch for 4.x 2017-06-19 15:34:51 +02:00
TuxSH
d819cfd58f Remove useless files 2017-06-19 15:21:15 +02:00
TuxSH
17828273a5 Revamp config format, add saving of Rosalina opt.
(menu combo & 3dsx title ID)
2017-06-18 22:31:21 +02:00
TuxSH
2363817265 Fix grey strides issue (maybe) 2017-06-17 01:52:08 +02:00
TuxSH
b31018ab17 Lower the priority of the Rosalina menu 2017-06-17 00:15:36 +02:00
TuxSH
c610ec3319 Virtually full support for 4.x sysNAND
(see also: previous commit)
2017-06-16 22:37:04 +02:00
TuxSH
b71dedccfc Full support for fw >= 6.x (tested)
Virtually full support for 5.x except that svcUnmapProcessMemoryEx will be forwarded to svcUnmapProcessMemory (both are equivalent for up to 64MB chunks)
2017-06-16 04:21:48 +02:00
TuxSH
9ccfacd06d Display IP in menus when either gdb/inputredir is enabled 2017-06-15 17:38:45 +02:00
TuxSH
12b561a27d Remove unused variables 2017-06-15 01:57:57 +02:00
TuxSH
cc41003e1c Fix exheader.h 2017-06-15 01:53:34 +02:00
TuxSH
3d534c9a81 Unschedule threads properly...
...instead of using a shitty yield when opening the Rosalina menu
2017-06-14 19:35:03 +02:00
TuxSH
24de7c5272 Fix indentation of gdb.c 2017-06-14 10:04:09 +02:00
TuxSH
a1b2ea2c5b Fix firmlaunch payload path bug 2017-06-14 02:05:32 +02:00
TuxSH
19d68b6df4 Adjust config mem values 2017-06-14 01:29:55 +02:00
TuxSH
2ab41dbd01 Fix firmlaunch bug 2017-06-13 23:08:32 +02:00
TuxSH
da30c0b0f0 Fix dfsr being displayed instead of fpexc 2017-06-13 02:53:53 +02:00
TuxSH
005684d865 Fix loader bugs
new-hbmenu now works with H&S, etc.
2017-06-13 02:37:27 +02:00
TuxSH
da1eff82ba Remove debugging line 2017-06-13 02:29:01 +02:00
TuxSH
a17311c955 Merge branch 'memregion-test' 2017-06-13 02:28:38 +02:00
TuxSH
e1d0602f25 Move the kext outside Rosalina
- Stability (tm)
- Boots 1s faster on N3DS
- (∩ ͡° ͜ʖ ͡°)⊃━☆゚
2017-06-13 02:00:41 +02:00
TuxSH
2ff9718510 Merge pull request #595 from Hikari-chin/master
Fix #593
2017-06-12 18:00:22 +02:00
Hikari-chin
33af9cfe09 Fix #593 2017-06-12 01:45:38 +00:00
Aurora
79709a7ae7 Merge pull request #594 from Margen67/master
Update issue template
2017-06-11 21:01:48 +02:00
Margen67
a796a70d01 Update issue template 2017-06-11 12:00:06 -07:00
TuxSH
53e2ef24f1 Refactor pattern for ir hook 2017-06-11 17:16:14 +01:00
Ezekiel Bethel
c0059c83ac inputredirection hook in ir:user cpp emulation => c-stick works in games now, also hook refactoring 2017-06-11 17:16:13 +01:00
Ezekiel Bethel
37eb21d297 poweroff/reboot for Rosalina misc. menu 2017-06-11 17:06:43 +01:00
Aurora Wright
52a18831a7 Minor style changes (2) 2017-06-10 03:06:16 +02:00
Aurora Wright
0d7cca7b20 Minor style changes 2017-06-10 02:55:55 +02:00
Aurora Wright
bea73c51ae Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-06-10 02:39:08 +02:00
Aurora Wright
0c68750056 Refactor payload loading, fix messy externs, add safety checks to Nintendo FIRMs, fix some Nintendo FIRMs not being loaded as payloads 2017-06-10 02:39:00 +02:00
TuxSH
ae8ea7da16 Revert PR due to breakage for a totally unrelated reason
(will be added back later)
2017-06-10 01:39:11 +02:00
TuxSH
69762c5dce Revert "Attempt fixing svcConnectToPortInitHook.s again"
This reverts commit 901d4992c0.
2017-06-09 20:48:01 +02:00
TuxSH
901d4992c0 Attempt fixing svcConnectToPortInitHook.s again 2017-06-09 18:10:02 +02:00
Aurora Wright
4d47d891d1 Fix max module size check, static-ify more strings 2017-06-09 17:29:26 +02:00
TuxSH
a7046909ec Use static const when appropriate 2017-06-09 14:26:51 +02:00
Aurora Wright
4bc95979de Revert #949d219c726e41cca84c873e7e200be14af13f63 (breaks building on *nix) 2017-06-09 13:44:04 +02:00
TuxSH
949d219c72 lolwut this fixes building on WSL
maybe memsearch is flasky on unaligned patterns, dunno
2017-06-09 05:00:38 +02:00
TuxSH
9a3d9aed30 Always enable ARM9 exceptions, update .gitignore 2017-06-09 02:31:14 +02:00
TuxSH
4d99143da0 Merge pull request #561 from SciresM/master
Add config option to disable exception vectors.
2017-06-09 00:17:14 +02:00
TuxSH
461035b212 Fix bug(s), refactor svcConnectToPortInitHook.s, cleanup 2017-06-08 21:35:41 +02:00
Michael Scire
0694ea8367 Add config option to disable exception vectors. 2017-06-07 17:48:30 -07:00
TuxSH
427a05997d Revert "Refactor fatalExceptionHandlers.s a bit"
This reverts commit 84d736c2eb.
2017-06-08 02:02:49 +02:00
TuxSH
84d736c2eb Refactor fatalExceptionHandlers.s a bit 2017-06-07 23:58:29 +02:00
TuxSH
a16d1ebe33 Refactor k11 main hook
Much less error-prone now.
2017-06-07 22:13:05 +02:00
Aurora Wright
43f3c84316 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-06-07 19:16:13 +02:00
Aurora Wright
44cafe3f46 Fix mismerges 2017-06-07 19:15:51 +02:00
TuxSH
76d7a035bd Fix country/state id spoofing 2017-06-07 01:06:39 +02:00
TuxSH
a5b638ae7b Fix uninitialized variable bugs 2017-06-06 21:04:13 +02:00
TuxSH
174089e4f3 Fix langemu bugs 2017-06-06 19:37:16 +02:00
TuxSH
4d219813fe Merge pull request #519 from sora10pls/master
Reference release notes in README.md
2017-06-06 02:52:32 +02:00
Aurora Wright
a798f453d2 Update gitignore 2017-06-06 02:17:58 +02:00
Aurora Wright
6ec21611c0 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-06-06 02:13:02 +02:00
Aurora Wright
31f4419eec Refactor screen functions, completely fix config not saving bug 2017-06-06 02:12:18 +02:00
Aurora Wright
60d136f9b5 Fix #491 2017-06-06 01:22:17 +02:00
TuxSH
0ba7f9dba0 Fix chainloader 2017-06-05 21:24:18 +02:00
TuxSH
0ac6db006a Work around a GDB bug (w/r/t packet size) 2017-06-05 21:23:17 +02:00
TuxSH
26dd61e4e6 Fix (work around) Nintendo own HM bug, GG Ninty 2017-06-05 20:28:44 +02:00
TuxSH
dda11206db Fix bug in fatalExceptionHandlers.s 2017-06-05 19:32:37 +02:00
Matt
e8565d30a9 Reference release notes in README.md 2017-06-05 10:15:49 -04:00
TuxSH
2d4c103854 Merge pull request #510 from T3CHNOLOG1C/master
fix typo in readme
2017-06-05 14:46:21 +02:00
T3CHNOLOG1C
d0b9e36908 fix typo in readme 2017-06-05 06:58:19 -04:00
142 changed files with 2420 additions and 1589 deletions

View File

@@ -1,6 +1,5 @@
<!--
-- 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
--
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
@@ -27,7 +26,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 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.-->
@@ -54,8 +53,6 @@ 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: ( )
Enable game patching: ( )
Show NAND or user string in System Settings: ( )
@@ -66,6 +63,8 @@ Patch ARM9 access: ( )
Set developer UNITINFO: ( )
Disable ARM11 exception handlers: ( )
--

8
.gitignore vendored
View File

@@ -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

View File

@@ -11,23 +11,39 @@ 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
@@ -42,8 +58,7 @@ 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
@@ -65,6 +80,7 @@ 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
@rm -rf $(dir_out) $(dir_build)
@@ -74,6 +90,7 @@ clean:
.PHONY: $(dir_arm11)
.PHONY: $(dir_chainloader)
.PHONY: $(dir_arm9_exceptions)
.PHONY: $(dir_k11_extension)
.PHONY: $(dir_loader)
.PHONY: $(dir_rosalina)
@@ -81,14 +98,14 @@ $(dir_out)/$(name)$(revision).7z: all
@mkdir -p "$(@D)"
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
$(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 +113,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 $<
@@ -121,9 +142,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),\

View File

@@ -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)).
---
@@ -16,7 +16,7 @@ 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!).
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!) and [makerom](https://github.com/Steveice10/buildtools/tree/master/3ds) (thanks @Steveice10!).
Finally just run `make` and everything should work!
You can find the compiled files in the `out` folder.

View File

@@ -37,7 +37,7 @@ extern u32 prepareForFirmlaunchSize;
extern volatile Arm11Operation operation;
static void initScreensSequence(u32 brightnessLevel)
static void initScreens(u32 brightnessLevel)
{
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
@@ -70,7 +70,6 @@ static void initScreensSequence(u32 brightnessLevel)
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
@@ -104,7 +103,6 @@ static void initScreensSequence(u32 brightnessLevel)
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
@@ -178,8 +176,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);
break;
case SETUP_FRAMEBUFFERS:
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);

View File

@@ -54,7 +54,7 @@ struct fb {
typedef enum
{
INIT_SCREENS_SEQUENCE = 0,
INIT_SCREENS = 0,
SETUP_FRAMEBUFFERS,
CLEAR_SCREENS,
SWAP_FRAMEBUFFERS,

View File

@@ -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];

View File

@@ -56,5 +56,5 @@ disableMpuAndJumpToEntrypoints:
@ Jump to the ARM9 entrypoint
mov r0, r4
mov r1, r5
ldr r2, =0x1BEEF
ldr r2, =0x2BEEF
bx r6

View File

@@ -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, \

View 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)
enum multiOptions
{
DEFAULTEMU = 0,
BRIGHTNESS,
SPLASH,
PIN,
NEWCPU
};
enum singleOptions
{
AUTOBOOTEMU = 0,
USEEMUFIRM,
LOADEXTFIRMSANDMODULES,
PATCHGAMES,
PATCHVERSTRING,
SHOWGBABOOT,
PATCHACCESS,
PATCHUNITINFO,
DISABLEARM11EXCHANDLERS
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -33,5 +33,6 @@
extern void *officialSVCs[0x7E];
void postprocessSvc(void);
void svcDefaultHandler(u8 svcId);
void *svcHook(u8 *pageEnd);

View File

@@ -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, ...);

View File

@@ -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);

View File

@@ -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);

View File

@@ -30,4 +30,4 @@
#include "kernel.h"
#include "svc.h"
void SetWifiEnabled(bool enable);
Result SetWifiEnabled(bool enable);

View File

@@ -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
View 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__ = .;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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}

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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

View 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);
}

View File

@@ -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;

View File

@@ -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:

View File

@@ -107,6 +107,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 +127,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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View 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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -45,7 +45,7 @@
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define SINGLE_PAYLOAD_BUTTONS (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)

View File

@@ -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)))
@@ -93,6 +93,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Patch ARM9 access",
"( ) Set developer UNITINFO",
"( ) Disable ARM11 exception handlers",
};
const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
@@ -151,13 +152,11 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"Enable overriding the region and\n"
"language configuration and the usage\n"
"of patched code binaries,\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"
"Enabling this requires the\n"
"archive patch to be applied.\n\n"
"Refer to the wiki for instructions.",
"Enable showing the current NAND/FIRM:\n\n"
@@ -186,6 +185,13 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"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 {
@@ -213,6 +219,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
{ .visible = true },
{ .visible = true },
{ .visible = true },
{ .visible = true },
{ .visible = true }
};
@@ -373,20 +380,22 @@ 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;
u32 newPinMode = MULTICONFIG(PIN);
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
else if(oldPinStatus) fileDelete(PIN_FILE);
writeConfig(true);
while(HID_PAD & PIN_BUTTONS);
wait(2000ULL);
}

View File

@@ -28,13 +28,13 @@
#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 0
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
@@ -58,7 +58,8 @@ enum singleOptions
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);

View File

@@ -33,6 +33,7 @@
#include "crypto.h"
#include "memory.h"
#include "emunand.h"
#include "strings.h"
#include "utils.h"
#include "fatfs/sdmmc/sdmmc.h"
@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -102,22 +102,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 +150,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 +173,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 +185,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 +205,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

View File

@@ -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);

View File

@@ -41,7 +41,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,15 +60,13 @@ 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"
};
@@ -113,8 +111,10 @@ 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]);
}
posY += SPACING_Y;

View File

@@ -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);

View File

@@ -291,6 +291,8 @@ static u32 calcSDSize(u8 *csd, int type)
static void InitSD()
{
*(vu32 *)0x10000020 = 0; //InitFS stuff
*(vu32 *)0x10000020 = 0x200; //InitFS stuff
*(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32
*(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32
*(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32

View File

@@ -39,7 +39,74 @@
#include "fmt.h"
#include "../build/bundled.h"
static inline bool loadFirmFromStorage(FirmwareType firmType)
static Firm *firm = (Firm *)0x20001000;
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
{
if(as <= bs && bs <= ae)
return true;
if(bs <= as && as <= be)
return true;
return false;
}
static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be)
{
if(as >= bs && ae <= be)
return true;
return false;
}
static bool checkFirm(u32 firmSize)
{
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
return false;
bool arm9EpFound = false,
arm11EpFound = false;
u32 size = 0x200;
for(u32 i = 0; i < 4; i++)
size += firm->section[i].size;
if(firmSize < size) return false;
for(u32 i = 0; i < 4; i++)
{
FirmSection *section = &firm->section[i];
//Allow empty sections
if(section->size == 0)
continue;
if((section->offset < 0x200) ||
(section->address + section->size < section->address) || //Overflow check
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) ||
((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))
return false;
__attribute__((aligned(4))) u8 hash[0x20];
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
if(memcmp(hash, section->hash, 0x20) != 0)
return false;
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
arm9EpFound = true;
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
arm11EpFound = true;
}
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
}
static inline u32 loadFirmFromStorage(FirmwareType firmType)
{
const char *firmwareFiles[] = {
"native.firm",
@@ -58,33 +125,136 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
if(!firmSize) return false;
if(!firmSize) return 0;
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
static const char *extFirmError = "The external FIRM is not valid.";
if(firmSize <= sizeof(Cxi) + 0x200) error(extFirmError);
if(memcmp(firm, "FIRM", 4) != 0)
{
if(firmSize <= sizeof(Cxi) + 0x400) error(extFirmError);
u8 cetk[0xA50];
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) ||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
error("The FIRM in /luma is encrypted or corrupted.");
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk))
error("The cetk is missing or corrupted.");
firmSize = decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize);
if(!firmSize) error("Unable to decrypt the external FIRM.");
}
if(!checkFirm(firmSize)) error("The external FIRM is invalid or corrupted.");
return firmSize;
}
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
{
//Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType);
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
u32 firmSize = decryptExeFs((Cxi *)firm);
if(!firmSize) error("Failed to decrypt the CTRNAND FIRM.");
if(!checkFirm(firmSize)) error("The CTRNAND FIRM is invalid or corrupted.");
if(!ISN3DS && *firmType == NATIVE_FIRM && firm->section[0].address == (u8 *)0x1FF80000)
{
//We can't boot < 3.x EmuNANDs
if(nandType != FIRMWARE_SYSNAND) error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
*firmType = NATIVE_FIRM1X2X;
}
bool loadedFromStorage = false;
if(loadFromStorage)
{
u32 result = loadFirmFromStorage(*firmType);
if(result != 0)
{
loadedFromStorage = true;
firmSize = result;
}
}
//Check that the FIRM is right for the console from the ARM9 section address
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
error("The FIRM in /luma is not for this console.");
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
return true;
if(loadedFromStorage || ISDEVUNIT)
{
firmVersion = 0xFFFFFFFF;
if(!ISN3DS && *firmType == NATIVE_FIRM)
{
__attribute__((aligned(4))) static const u8 hashes[3][0x20] = {
{0x39, 0x75, 0xB5, 0x28, 0x24, 0x5E, 0x8B, 0x56, 0xBC, 0x83, 0x79, 0x41, 0x09, 0x2C, 0x42, 0xE6,
0x26, 0xB6, 0x80, 0x59, 0xA5, 0x56, 0xF9, 0xF9, 0x6E, 0xF3, 0x63, 0x05, 0x58, 0xDF, 0x35, 0xEF},
{0x81, 0x9E, 0x71, 0x58, 0xE5, 0x44, 0x73, 0xF7, 0x48, 0x78, 0x7C, 0xEF, 0x5E, 0x30, 0xE2, 0x28,
0x78, 0x0B, 0x21, 0x23, 0x94, 0x63, 0xE8, 0x4E, 0x06, 0xBB, 0xD6, 0x8D, 0xA0, 0x99, 0xAE, 0x98},
{0x1D, 0xD5, 0xB0, 0xC2, 0xD9, 0x4A, 0x4A, 0xF3, 0x23, 0xDD, 0x2F, 0x65, 0x21, 0x95, 0x9B, 0x7E,
0xF2, 0x71, 0x7E, 0xB6, 0x7A, 0x3A, 0x74, 0x78, 0x0D, 0xE3, 0xB5, 0x0C, 0x2B, 0x7F, 0x85, 0x37}
};
u32 i;
for(i = 0; i < 3; i++) if(memcmp(firm->section[1].hash, hashes[i], 0x20) == 0) break;
switch(i)
{
case 0:
firmVersion = 0x18;
break;
case 1:
firmVersion = 0x1D;
break;
case 2:
firmVersion = 0x1F;
break;
}
}
}
return firmVersion;
}
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
void loadHomebrewFirm(u32 pressed)
{
u32 srcModuleSize;
const char *extModuleSizeError = "The external FIRM modules are too large.";
char path[10 + 255];
bool found = !pressed ? payloadMenu(path) : findPayload(path, pressed);
if(!found) return;
u32 maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm),
payloadSize = fileRead(firm, path, maxPayloadSize);
if(payloadSize <= 0x200 || !checkFirm(payloadSize)) error("The payload is invalid or corrupted.");
char absPath[24 + 255];
if(isSdMode) sprintf(absPath, "sdmc:/luma/%s", path);
else sprintf(absPath, "nand:/rw/luma/%s", path);
char *argv[2] = {absPath, (char *)fbs};
initScreens();
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
}
static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool loadFromStorage)
{
u32 srcModuleSize,
nbModules = 0;
u32 nbModules = 0,
isCustomModule = false;
struct
{
char name[8];
@@ -97,35 +267,36 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
{
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
moduleList[nbModules].src = src;
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
}
if(firmType == NATIVE_FIRM)
if(firmType == NATIVE_FIRM && (ISN3DS || firmVersion >= 0x1D))
{
//2) Merge that info with our own modules'
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
//2) Merge that info with our own modules'
for(u8 *src = (u8 *)0x18180000; src < (u8 *)(0x18180000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
{
const char *name = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
u32 i;
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; i++);
if(i == nbModules) isCustomModule = true;
for(i = 0; i < 5 && memcmp(name, moduleList[i].name, 8) != 0; i++);
if(i == 5)
{
nbModules++;
memcpy(moduleList[i].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
}
memcpy(moduleList[i].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
moduleList[i].src = src;
srcModuleSize = moduleList[i].size = ((Cxi *)src)->ncch.contentSize * 0x200;
}
if(isCustomModule) nbModules++;
}
//3) Read or copy the modules
u8 *dst = firm->section[0].address;
for(u32 i = 0, dstModuleSize; i < nbModules; i++)
const char *extModuleSizeError = "The external FIRM modules are too large.";
for(u32 i = 0, dstModuleSize, maxModuleSize = firmType == NATIVE_FIRM ? 0x80000 : 0x600000; i < nbModules; i++, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
{
dstModuleSize = 0;
if(loadFromStorage)
{
char fileName[24];
@@ -137,7 +308,7 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
if(dstModuleSize != 0)
{
if(dstModuleSize > 0x60000) error(extModuleSizeError);
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
@@ -145,63 +316,26 @@ static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
memcmp(moduleList[i].name, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
error("An external FIRM module is invalid or corrupted.");
dst += dstModuleSize;
continue;
}
}
if(!dstModuleSize)
{
memcpy(dst, moduleList[i].src, moduleList[i].size);
dst += moduleList[i].size;
}
dstModuleSize = moduleList[i].size;
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
memcpy(dst, moduleList[i].src, dstModuleSize);
}
//4) Patch NATIVE_FIRM if necessary
if(isCustomModule)
if(nbModules == 6)
{
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, (u8 *)firm + firm->section[1].offset, firm->section[1].size) != 0)
error("Failed to inject custom sysmodule");
}
}
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
{
//Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType);
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
bool mustLoadFromStorage = false;
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
{
if(firmVersion < 0x18)
{
//We can't boot < 3.x EmuNANDs
if(nandType != FIRMWARE_SYSNAND)
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
*firmType = NATIVE_FIRM1X2X;
}
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD/CTRNAND
else if(firmVersion < 0x25) mustLoadFromStorage = true;
}
if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF;
else
{
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
if(ISDEVUNIT) firmVersion = 0xFFFFFFFF;
}
return firmVersion;
}
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch)
{
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
@@ -212,7 +346,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
kernel9Loader((Arm9Bin *)arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
}
//Find the Process9 .code location, size and memory address
u32 process9Size,
process9MemAddr;
@@ -228,16 +362,18 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
ret = 0;
installMMUHook(arm11Section1, firm->section[1].size, &freeK11Space);
installK11MainHook(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11SvcTable, arm11ExceptionsPage, &freeK11Space);
installSvcConnectToPortInitHook(arm11SvcTable, arm11ExceptionsPage, &freeK11Space);
installSvcCustomBackdoor(arm11SvcTable, &freeK11Space, arm11ExceptionsPage);
//Skip on FIRMs < 4.0
if(ISN3DS || firmVersion >= 0x1D)
{
ret += installK11Extension(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11ExceptionsPage, &freeK11Space);
ret += patchKernel11(arm11Section1, firm->section[1].size, baseK11VA, arm11SvcTable, arm11ExceptionsPage);
}
//Apply signature patches
ret += patchSignatureChecks(process9Offset, process9Size);
//Apply EmuNAND patches
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address);
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion);
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH
else ret += patchFirmWrites(process9Offset, process9Size);
@@ -252,12 +388,8 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
ret += patchNandNcchEncryptionCheck(process9Offset, process9Size);
}
//11.0 FIRM patches
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
{
//Apply anti-anti-DG patches
ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion);
}
//Apply anti-anti-DG patches on 11.0+
if(firmVersion >= (ISN3DS ? 0x21 : 0x52)) ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion);
//Apply UNITINFO patches
if(doUnitinfoPatch)
@@ -266,18 +398,14 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
if(!ISDEVUNIT) ret += patchCheckForDevCommonKey(process9Offset, process9Size);
}
if(enableExceptionHandlers)
{
//ARM9 exception handlers
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
ret += patchKernel9Panic(arm9Section, kernel9Size);
}
//ARM9 exception handlers
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
ret += patchKernel9Panic(arm9Section, kernel9Size);
if(CONFIG(PATCHACCESS))
ret += patchP9AccessChecks(process9Offset, process9Size);
if(CONFIG(PATCHACCESS)) ret += patchP9AccessChecks(process9Offset, process9Size);
mergeSection0(NATIVE_FIRM, loadFromStorage);
mergeSection0(NATIVE_FIRM, firmVersion, loadFromStorage);
firm->section[0].size = 0;
return ret;
@@ -315,7 +443,7 @@ u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
if(loadFromStorage)
{
mergeSection0(TWL_FIRM, true);
mergeSection0(TWL_FIRM, 0, true);
firm->section[0].size = 0;
}
@@ -349,14 +477,14 @@ u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
if(loadFromStorage)
{
mergeSection0(AGB_FIRM, true);
mergeSection0(AGB_FIRM, 0, true);
firm->section[0].size = 0;
}
return ret;
}
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
u32 patch1x2xNativeAndSafeFirm(void)
{
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
@@ -379,81 +507,13 @@ u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
ret += ISN3DS ? patchSignatureChecks(process9Offset, process9Size) : patchOldSignatureChecks(process9Offset, process9Size);
if(enableExceptionHandlers)
{
//ARM9 exception handlers
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
}
//ARM9 exception handlers
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
return ret;
}
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
{
if(as <= bs && bs <= ae)
return true;
if(bs <= as && as <= be)
return true;
return false;
}
static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be)
{
if(as >= bs && ae <= be)
return true;
return false;
}
bool checkFirmPayload(u32 payloadSize)
{
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
return false;
bool arm9EpFound = false,
arm11EpFound = false;
u32 size = 0x200;
for(u32 i = 0; i < 4; i++)
size += firm->section[i].size;
if(size != payloadSize) return false;
for(u32 i = 0; i < 4; i++)
{
FirmSection *section = &firm->section[i];
//Allow empty sections
if(section->size == 0)
continue;
if((section->offset < 0x200) ||
(section->address + section->size < section->address) || //Overflow check
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) ||
((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) &&
(!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))
return false;
__attribute__((aligned(4))) u8 hash[0x20];
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
if(memcmp(hash, section->hash, 0x20) != 0)
return false;
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
arm9EpFound = true;
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
arm11EpFound = true;
}
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
}
void launchFirm(int argc, char **argv)
{
u32 *chainloaderAddress = (u32 *)0x01FF9000;
@@ -463,5 +523,5 @@ void launchFirm(int argc, char **argv)
memcpy(chainloaderAddress, chainloader_bin, chainloader_bin_size);
// No need to flush caches here, the chainloader is in ITCM
((void (*)(int, char **, u32))chainloaderAddress)(argc, argv, 0x0000BEEF);
((void (*)(int, char **, Firm *))chainloaderAddress)(argc, argv, firm);
}

View File

@@ -29,13 +29,10 @@
#include "types.h"
#include "3dsheaders.h"
static Firm *const firm = (Firm *const)0x20001000;
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
void loadHomebrewFirm(u32 pressed);
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch);
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
bool checkFirmPayload(u32 payloadSize);
u32 patch1x2xNativeAndSafeFirm(void);
void launchFirm(int argc, char **argv);

View File

@@ -263,7 +263,7 @@ u32 vsprintf(char *buf, const char *fmt, va_list args)
//Integer number formats - set up the flags and "break"
case 'X':
flags |= UPPERCASE;
//Falls through
case 'x':
isHex = true;
break;
@@ -271,7 +271,7 @@ u32 vsprintf(char *buf, const char *fmt, va_list args)
case 'd':
case 'i':
flags |= SIGN;
//Falls through
case 'u':
isHex = false;
break;

View File

@@ -33,7 +33,6 @@
#include "screen.h"
#include "draw.h"
#include "utils.h"
#include "config.h"
#include "fatfs/ff.h"
#include "buttons.h"
#include "firm.h"
@@ -122,68 +121,44 @@ void fileDelete(const char *path)
f_unlink(path);
}
void loadPayload(u32 pressed, const char *payloadPath)
bool findPayload(char *path, u32 pressed)
{
u32 payloadSize = 0,
maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
const char *pattern;
char absPath[24 + _MAX_LFN];
char path[10 + _MAX_LFN];
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
else if(pressed & BUTTON_UP) pattern = PATTERN("up");
else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
else if(pressed & BUTTON_START) pattern = PATTERN("start");
else if(pressed & BUTTON_B) pattern = PATTERN("b");
else if(pressed & BUTTON_X) pattern = PATTERN("x");
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
else if(pressed & BUTTON_A) pattern = PATTERN("a");
else pattern = PATTERN("select");
if(payloadPath == NULL)
{
const char *pattern;
DIR dir;
FILINFO info;
FRESULT result;
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
else if(pressed & BUTTON_UP) pattern = PATTERN("up");
else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
else if(pressed & BUTTON_START) pattern = PATTERN("start");
else if(pressed & BUTTON_B) pattern = PATTERN("b");
else if(pressed & BUTTON_X) pattern = PATTERN("x");
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
else if(pressed & BUTTON_A) pattern = PATTERN("a");
else pattern = PATTERN("select");
result = f_findfirst(&dir, &info, "payloads", pattern);
DIR dir;
FILINFO info;
FRESULT result;
if(result != FR_OK) return false;
result = f_findfirst(&dir, &info, "payloads", pattern);
f_closedir(&dir);
if(result != FR_OK) return;
if(!info.fname[0]) return false;
f_closedir(&dir);
sprintf(path, "payloads/%s", info.fname);
if(!info.fname[0]) return;
sprintf(path, "payloads/%s", info.fname);
}
else sprintf(path, "%s", payloadPath);
payloadSize = fileRead(firm, path, maxPayloadSize);
if(payloadSize <= 0x200 || !checkFirmPayload(payloadSize)) return;
writeConfig(true);
if(isSdMode) sprintf(absPath, "sdmc:/luma/%s", path);
else sprintf(absPath, "nand:/rw/luma/%s", path);
char *argv[2] = {absPath, (char *)fbs};
initScreens();
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
return true;
}
void payloadMenu(void)
bool payloadMenu(char *path)
{
DIR dir;
char path[62] = "payloads";
if(f_opendir(&dir, path) != FR_OK) return;
if(f_opendir(&dir, "payloads") != FR_OK) return false;
FILINFO info;
u32 payloadNum = 0;
@@ -208,7 +183,7 @@ void payloadMenu(void)
f_closedir(&dir);
if(!payloadNum) return;
if(!payloadNum) return false;
u32 pressed = 0,
selectedPayload = 0;
@@ -264,12 +239,14 @@ void payloadMenu(void)
if(pressed != BUTTON_START)
{
sprintf(path, "payloads/%s.firm", payloadList[selectedPayload]);
loadPayload(0, path);
error("The payload is too large or corrupted.");
return true;
}
while(HID_PAD & MENU_BUTTONS);
wait(2000ULL);
return false;
}
u32 firmRead(void *dest, u32 firmType)
@@ -311,7 +288,7 @@ u32 firmRead(void *dest, u32 firmType)
//Complete the string with the .app name
sprintf(path, "%s/%08x.app", folderPath, firmVersion);
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x400) firmVersion = 0xFFFFFFFF;
exit:
return firmVersion;

View File

@@ -35,7 +35,7 @@ u32 fileRead(void *dest, const char *path, u32 maxSize);
u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size);
void fileDelete(const char *path);
void loadPayload(u32 pressed, const char *payloadPath);
void payloadMenu(void);
bool findPayload(char *path, u32 pressed);
bool payloadMenu(char *path);
u32 firmRead(void *dest, u32 firmType);
void findDumpFile(const char *folderPath, char *fileName);

View File

@@ -72,7 +72,7 @@ void main(int argc, char **argv, u32 magicWord)
}
else
{
const char argv[] = "firm0:";
static const char argv[] = "firm0:";
for(u32 i = 0; i < sizeof(argv); i++) //Copy and convert the path to UTF-16
launchedPath[i] = argv[i];
}
@@ -154,7 +154,7 @@ void main(int argc, char **argv, u32 magicWord)
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
//Prevent multiple boot options-forcing
isNoForceFlagSet = true;
if(nandType != BOOTCFG_NAND || firmSource != BOOTCFG_FIRM) isNoForceFlagSet = true;
goto boot;
}
@@ -205,13 +205,15 @@ void main(int argc, char **argv, u32 magicWord)
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
bool autoBootEmu = CONFIG(AUTOBOOTEMU);
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
{
payloadMenu();
loadHomebrewFirm(0);
pressed = HID_PAD;
}
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
else if((((pressed & SINGLE_PAYLOAD_BUTTONS) || (!autoBootEmu && (pressed & DPAD_BUTTONS))) && !(pressed & (BUTTON_L1 | BUTTON_R1))) ||
(((pressed & L_PAYLOAD_BUTTONS) || (autoBootEmu && (pressed & DPAD_BUTTONS))) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed);
if(splashMode == 2) loadSplash();
@@ -235,7 +237,7 @@ void main(int argc, char **argv, u32 magicWord)
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else firmSource = nandType = (CONFIG(AUTOBOOTEMU) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
else firmSource = nandType = (autoBootEmu == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
@@ -279,21 +281,21 @@ boot:
if(!isFirmlaunch)
{
configData.config = (configData.config & 0xFFFFFF80) | ((u32)isNoForceFlagSet << 6) | ((u32)firmSource << 3) | (u32)nandType;
configData.bootConfig = ((u32)isNoForceFlagSet << 6) | ((u32)firmSource << 3) | (u32)nandType;
writeConfig(false);
}
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
u32 firmVersion = loadNintendoFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), enableExceptionHandlers = CONFIG(PATCHUNITINFO);
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO);
u32 res;
switch(firmType)
{
case NATIVE_FIRM:
res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isSafeMode, doUnitinfoPatch);
break;
case TWL_FIRM:
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
@@ -304,7 +306,7 @@ boot:
case SAFE_FIRM:
case SYSUPDATER_FIRM:
case NATIVE_FIRM1X2X:
res = patch1x2xNativeAndSafeFirm(enableExceptionHandlers);
res = patch1x2xNativeAndSafeFirm();
break;
}

View File

@@ -40,13 +40,12 @@ void memcpy(void *dest, const void *src, u32 size)
destc[i] = srcc[i];
}
void *memset(void *dest, u32 value, u32 size)
void memset(void *dest, u32 filler, u32 size)
{
u8 *destc = (u8 *)dest;
for(u32 i = 0; i < size; i++) destc[i] = (u8)value;
return dest;
for(u32 i = 0; i < size; i++)
destc[i] = (u8)filler;
}
void memset32(void *dest, u32 filler, u32 size)

View File

@@ -34,7 +34,7 @@
#include "types.h"
void memcpy(void *dest, const void *src, u32 size);
void *memset(void *dest, u32 value, u32 size) __attribute__((used));
void memset(void *dest, u32 filler, u32 size) __attribute__((used));
void memset32(void *dest, u32 filler, u32 size);
int memcmp(const void *buf1, const void *buf2, u32 size);
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);

View File

@@ -57,7 +57,7 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
{
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5};
static const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5};
*arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
if(*arm11ExceptionsPage == NULL) error("Failed to get Kernel11 data.");
@@ -78,120 +78,193 @@ u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 *
return arm11SvcTable;
}
void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space)
// For ARM prologs in the form of: push {regs} ... sub sp, #off (this obviously doesn't intend to cover all cases)
static inline u32 computeARMFrameSize(const u32 *prolog)
{
const u8 pattern[] = {0x0E, 0x32, 0xA0, 0xE3, 0x02, 0xC2, 0xA0, 0xE3};
const u32 *off;
u32 *off = (u32 *)memsearch(pos, pattern, size, 8);
for(off = prolog; (*off >> 16) != 0xE92D; off++); // look for stmfd sp! = push
u32 nbPushedRegs = 0;
for(u32 val = *off & 0xFFFF; val != 0; val >>= 1) // 1 bit = 1 pushed register
nbPushedRegs += val & 1;
for(; (*off >> 8) != 0xE24DD0; off++); // look for sub sp, #offset
u32 localVariablesSpaceSize = *off & 0xFF;
memcpy(*freeK11Space, mmuHook_bin, mmuHook_bin_size);
*off = MAKE_BRANCH_LINK(off, *freeK11Space);
(*freeK11Space) += mmuHook_bin_size;
return 4 * nbPushedRegs + localVariablesSpaceSize;
}
void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space)
static inline u32 *getKernel11HandlerVAPos(u8 *pos, u32 *arm11ExceptionsPage, u32 baseK11VA, u32 id)
{
const u8 pattern[] = {0x00, 0x00, 0xA0, 0xE1, 0x03, 0xF0, 0x20, 0xE3, 0xFD, 0xFF, 0xFF, 0xEA};
u32 off = ((-((arm11ExceptionsPage[id] & 0xFFFFFF) << 2)) & (0xFFFFFF << 2)) - 8;
u32 pointedInstructionVA = 0xFFFF0000 + 4 * id - off;
return (u32 *)(pos + pointedInstructionVA - baseK11VA + 8);
}
u32 *off = (u32 *)memsearch(pos, pattern, size, 12);
// look for cpsie i and place our function call in the nop 2 instructions before
while(*off != 0xF1080080) off--;
off -= 2;
memcpy(*freeK11Space, k11MainHook_bin, k11MainHook_bin_size);
u32 relocBase = 0xFFFF0000 + (*freeK11Space - (u8 *)arm11ExceptionsPage);
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase);
off = (u32 *)(pos + (arm11SvcTable[0x50] - baseK11VA)); //svcBindInterrupt
while(off[0] != 0xE1A05000 || off[1] != 0xE2100102 || off[2] != 0x5A00000B) off++;
off--;
signed int offset = (*off & 0xFFFFFF) << 2;
offset = offset << 6 >> 6; // sign extend
offset += 8;
u32 InterruptManager_mapInterrupt = baseK11VA + ((u8 *)off - pos) + offset;
u32 interruptManager = *(u32 *)(off - 4 + (*(off - 6) & 0xFFF) / 4);
off = (u32 *)memsearch(*freeK11Space, "bind", k11MainHook_bin_size, 4);
*off++ = InterruptManager_mapInterrupt;
// Relocate stuff
*off++ += relocBase;
*off++ += relocBase;
off++;
*off++ = interruptManager;
off += 10;
struct CfwInfo
u32 installK11Extension(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11ExceptionsPage, u8 **freeK11Space)
{
//The parameters to be passed on to the kernel ext
//Please keep that in sync with the definition in k11_extension/source/main.c
struct KExtParameters
{
char magic[4];
u32 __attribute__((aligned(0x400))) L2MMUTableFor0x40000000[256];
u32 basePA;
void *originalHandlers[4];
u32 L1MMUTableAddrs[4];
u8 versionMajor;
u8 versionMinor;
u8 versionBuild;
u8 flags;
struct CfwInfo
{
char magic[4];
u32 commitHash;
u8 versionMajor;
u8 versionMinor;
u8 versionBuild;
u8 flags;
u32 config;
} __attribute__((packed)) *info = (struct CfwInfo *)off;
u32 commitHash;
const char *rev = REVISION;
u16 configFormatVersionMajor, configFormatVersionMinor;
u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo;
} info;
};
static const u8 patternHook1[] = {0x02, 0xC2, 0xA0, 0xE3, 0xFF}; //MMU setup hook
static const u8 patternHook2[] = {0x08, 0x00, 0xA4, 0xE5, 0x02, 0x10, 0x80, 0xE0, 0x08, 0x10, 0x84, 0xE5}; //FCRAM layout setup hook
static const u8 patternHook3_4[] = {0x00, 0x00, 0xA0, 0xE1, 0x03, 0xF0, 0x20, 0xE3, 0xFD, 0xFF, 0xFF, 0xEA}; //SGI0 setup code, etc.
//Our kernel11 extension is initially loaded in VRAM
u32 kextTotalSize = *(u32 *)0x18000020 - 0x40000000;
u32 dstKextPA = (ISN3DS ? 0x2E000000 : 0x26C00000) - kextTotalSize;
u32 *hookVeneers = (u32 *)*freeK11Space;
u32 relocBase = 0xFFFF0000 + (*freeK11Space - (u8 *)arm11ExceptionsPage);
hookVeneers[0] = 0xE51FF004; //ldr pc, [pc, #-8+4]
hookVeneers[1] = 0x18000004;
hookVeneers[2] = 0xE51FF004;
hookVeneers[3] = 0x40000000;
hookVeneers[4] = 0xE51FF004;
hookVeneers[5] = 0x40000008;
hookVeneers[6] = 0xE51FF004;
hookVeneers[7] = 0x4000000C;
(*freeK11Space) += 32;
//MMU setup hook
u32 *off = (u32 *)memsearch(pos, patternHook1, size, sizeof(patternHook1));
if(off == NULL) return 1;
*off = MAKE_BRANCH_LINK(off, hookVeneers);
//Most important hook: FCRAM layout setup hook
off = (u32 *)memsearch(pos, patternHook2, size, sizeof(patternHook2));
if(off == NULL) return 1;
off += 2;
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase + 8);
//Bind SGI0 hook
//Look for cpsie i and place our hook in the nop 2 instructions before
off = (u32 *)memsearch(pos, patternHook3_4, size, 12);
if(off == NULL) return 1;
for(; *off != 0xF1080080; off--);
off -= 2;
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase + 16);
//Config hook (after the configuration memory fields have been filled)
for(; *off != 0xE1A00000; off++);
off += 4;
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase + 24);
struct KExtParameters *p = (struct KExtParameters *)(*(u32 *)0x18000024 - 0x40000000 + 0x18000000);
p->basePA = dstKextPA;
for(u32 i = 0; i < 4; i++)
{
u32 *handlerPos = getKernel11HandlerVAPos(pos, arm11ExceptionsPage, baseK11VA, 1 + i);
p->originalHandlers[i] = (void *)*handlerPos;
*handlerPos = 0x40000010 + 4 * i;
}
struct CfwInfo *info = &p->info;
memcpy(&info->magic, "LUMA", 4);
info->commitHash = COMMIT_HASH;
info->configFormatVersionMajor = configData.formatVersionMajor;
info->configFormatVersionMinor = configData.formatVersionMinor;
info->config = configData.config;
info->versionMajor = (u8)(rev[1] - '0');
info->versionMinor = (u8)(rev[3] - '0');
info->multiConfig = configData.multiConfig;
info->bootConfig = configData.bootConfig;
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
info->versionMajor = VERSION_MAJOR;
info->versionMinor = VERSION_MINOR;
info->versionBuild = VERSION_BUILD;
if(rev[4] == '.')
info->versionBuild = (u8)(rev[5] - '0');
const char *revpos;
for(revpos = rev + 4; *revpos != 0 && *revpos != '-'; revpos++);
bool isRelease = *revpos != '-';
if(isRelease) info->flags = 1;
if(ISRELEASE) info->flags = 1;
if(ISN3DS) info->flags |= 1 << 4;
if(isSafeMode) info->flags |= 1 << 5;
if(isSdMode) info->flags |= 1 << 6;
(*freeK11Space) += k11MainHook_bin_size;
return 0;
}
void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space)
u32 patchKernel11(u8 *pos, u32 size, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage)
{
u32 addr = 0xFFFF0000 + (u32)*freeK11Space - (u32)arm11ExceptionsPage;
u32 svcSleepThreadAddr = arm11SvcTable[0x0A], svcConnectToPortAddr = arm11SvcTable[0x2D];
static const u8 patternKPanic[] = {0x02, 0x0B, 0x44, 0xE2};
static const u8 patternKThreadDebugReschedule[] = {0x34, 0x20, 0xD4, 0xE5, 0x00, 0x00, 0x55, 0xE3, 0x80, 0x00, 0xA0, 0x13};
arm11SvcTable[0x2D] = addr;
memcpy(*freeK11Space, svcConnectToPortInitHook_bin, svcConnectToPortInitHook_bin_size);
//Assumption: ControlMemory, DebugActiveProcess and KernelSetState are in the first 0x20000 bytes
//Patch ControlMemory
u8 *instrPos = pos + (arm11SvcTable[1] + 20 - baseK11VA);
s32 displ = (*(u32 *)instrPos & 0xFFFFFF) << 2;
displ = (displ << 6) >> 6; // sign extend
u32 *off = (u32 *)memsearch(*freeK11Space, "orig", svcConnectToPortInitHook_bin_size, 4);
off[0] = svcConnectToPortAddr;
off[1] = svcSleepThreadAddr;
u8 *ControlMemoryPos = instrPos + 8 + displ;
u32 *off;
(*freeK11Space) += svcConnectToPortInitHook_bin_size;
}
/*
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.
*/
for(off = (u32 *)ControlMemoryPos; (off[0] & 0xFFF0FFFF) != 0xE3500001 || (off[1] & 0xFFFF0FFF) != 0x13A00000; off++);
off -= 2;
*off = 0xE59D0000 | (*off & 0x0000F000) | (8 + computeARMFrameSize((u32 *)ControlMemoryPos)); // ldr r0, [sp, #(frameSize + 8)]
void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage)
{
memcpy(*freeK11Space, svcCustomBackdoor_bin, svcCustomBackdoor_bin_size);
*((u32 *)*freeK11Space + 1) = arm11SvcTable[0x2F]; // temporary location
arm11SvcTable[0x2F] = 0xFFFF0000 + *freeK11Space - (u8 *)arm11ExceptionsPage;
(*freeK11Space) += svcCustomBackdoor_bin_size;
//Patch DebugActiveProcess
for(off = (u32 *)(pos + (arm11SvcTable[0x60] - baseK11VA)); *off != 0xE3110001; off++);
*off = 0xE3B01001; // tst r1, #1 -> movs r1, #1
for(off = (u32 *)(pos + (arm11SvcTable[0x7C] - baseK11VA)); off[0] != 0xE5D00001 || off[1] != 0xE3500000; off++);
off[2] = 0xE1A00000; // in case 6: beq -> nop
//Patch kernelpanic
off = (u32 *)memsearch(pos, patternKPanic, size, sizeof(patternKPanic));
if(off == NULL)
return 1;
off[-6] = 0xE12FFF7E;
//Redirect enableUserExceptionHandlersForCPUExc (= true)
for(off = arm11ExceptionsPage; *off != 0x96007F9; off++);
off[1] = 0x40000028;
off = (u32 *)memsearch(pos, patternKThreadDebugReschedule, size, sizeof(patternKThreadDebugReschedule));
if(off == NULL)
return 1;
off[-5] = 0xE51FF004;
off[-4] = 0x4000002C;
return 0;
}
u32 patchSignatureChecks(u8 *pos, u32 size)
{
//Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
static const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
@@ -208,8 +281,8 @@ u32 patchSignatureChecks(u8 *pos, u32 size)
u32 patchOldSignatureChecks(u8 *pos, u32 size)
{
// Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0xBD, 0xE7},
pattern2[] = {0xB5, 0x23, 0x4E, 0x0C};
static const u8 pattern[] = {0xC0, 0x1C, 0xBD, 0xE7},
pattern2[] = {0xB5, 0x23, 0x4E, 0x0C};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
@@ -226,7 +299,7 @@ u32 patchOldSignatureChecks(u8 *pos, u32 size)
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
{
//Look for firmlaunch code
const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
static const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
u32 pathLen;
for(pathLen = 0; pathLen < 41 && launchedPath[pathLen] != 0; pathLen++);
@@ -262,7 +335,7 @@ u32 patchFirmWrites(u8 *pos, u32 size)
if(off == NULL) return 1;
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
static const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern));
@@ -277,7 +350,7 @@ u32 patchFirmWrites(u8 *pos, u32 size)
u32 patchOldFirmWrites(u8 *pos, u32 size)
{
//Look for FIRM writing code
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
static const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -291,7 +364,7 @@ u32 patchOldFirmWrites(u8 *pos, u32 size)
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion)
{
const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02};
static const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02};
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
@@ -307,7 +380,7 @@ u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion)
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size)
{
const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08};
static const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -321,7 +394,7 @@ u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size)
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size)
{
const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A};
static const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -335,7 +408,7 @@ u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size)
u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
{
const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00};
static const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -348,8 +421,8 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size)
{
const u8 moduleLoadingPattern[] = {0xE2, 0x05, 0x00, 0x57},
modulePidPattern[] = {0x06, 0xA0, 0xE1, 0xF2}; //GetSystemInfo
static const u8 moduleLoadingPattern[] = {0xE2, 0x05, 0x00, 0x57},
modulePidPattern[] = {0x06, 0xA0, 0xE1, 0xF2}; //GetSystemInfo
u8 *off = memsearch(pos, moduleLoadingPattern, size, 4);
@@ -375,7 +448,7 @@ u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size)
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
{
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
static const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -409,7 +482,7 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
//Stub svcBreak with "bkpt 65535" so we can debug the panic
//Look for the svc handler
const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
static const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -425,7 +498,7 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
u32 patchKernel9Panic(u8 *pos, u32 size)
{
const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0};
static const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -439,7 +512,7 @@ u32 patchKernel9Panic(u8 *pos, u32 size)
u32 patchP9AccessChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x00, 0x08, 0x49, 0x68};
static const u8 pattern[] = {0x00, 0x08, 0x49, 0x68};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -455,7 +528,7 @@ u32 patchP9AccessChecks(u8 *pos, u32 size)
u32 patchUnitInfoValueSet(u8 *pos, u32 size)
{
//Look for UNITINFO value being set during kernel sync
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
static const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
@@ -469,7 +542,7 @@ u32 patchUnitInfoValueSet(u8 *pos, u32 size)
u32 patchLgySignatureChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49};
static const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -485,7 +558,7 @@ u32 patchLgySignatureChecks(u8 *pos, u32 size)
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F};
static const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -499,7 +572,7 @@ u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size)
u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0};
static const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -513,7 +586,7 @@ u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size)
u32 patchTwlWhitelistChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x22, 0x00, 0x20, 0x30};
static const u8 pattern[] = {0x22, 0x00, 0x20, 0x30};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -527,7 +600,7 @@ u32 patchTwlWhitelistChecks(u8 *pos, u32 size)
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion)
{
const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E};
static const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E};
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
@@ -547,7 +620,7 @@ u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion)
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD};
static const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -561,7 +634,7 @@ u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size)
u32 patchTwlShaHashChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22};
static const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22};
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
@@ -575,7 +648,7 @@ u32 patchTwlShaHashChecks(u8 *pos, u32 size)
u32 patchAgbBootSplash(u8 *pos, u32 size)
{
const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF};
static const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF};
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));

View File

@@ -37,14 +37,10 @@
#include "types.h"
extern CfgData configData;
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage);
void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space);
void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space);
void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space);
void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage);
u32 installK11Extension(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11ExceptionsPage, u8 **freeK11Space);
u32 patchKernel11(u8 *pos, u32 size, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage);
u32 patchSignatureChecks(u8 *pos, u32 size);
u32 patchOldSignatureChecks(u8 *pos, u32 size);
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);

View File

@@ -40,7 +40,7 @@
static char pinKeyToLetter(u32 pressed)
{
const char keys[] = "AB--RLUD--XY";
static const char *keys = "AB--RLUD--XY";
u32 i;
for(i = 31; pressed > 1; i--) pressed /= 2;
@@ -151,7 +151,7 @@ bool verifyPin(u32 pinMode)
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", lengthBlock[0]);
const char *messageFile = "pinmessage.txt";
static const char *messageFile = "pinmessage.txt";
char message[801];
u32 messageSize = fileRead(message, messageFile, sizeof(message) - 1);

View File

@@ -35,7 +35,19 @@
#include "i2c.h"
#include "utils.h"
struct fb fbs[2];
struct fb fbs[2] =
{
{
.top_left = (u8 *)0x18300000,
.top_right = (u8 *)0x18300000,
.bottom = (u8 *)0x18346500,
},
{
.top_left = (u8 *)0x18400000,
.top_right = (u8 *)0x18400000,
.bottom = (u8 *)0x18446500,
},
};
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
@@ -78,45 +90,29 @@ void clearScreens(bool isAlternate)
invokeArm11Function(CLEAR_SCREENS);
}
static void initScreensSequence(void)
{
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
invokeArm11Function(INIT_SCREENS_SEQUENCE);
}
static void setupFramebuffers(void)
{
fbs[0].top_left = (u8 *)0x18300000;
fbs[1].top_left = (u8 *)0x18400000;
fbs[0].top_right = (u8 *)0x18300000;
fbs[1].top_right = (u8 *)0x18400000;
fbs[0].bottom = (u8 *)0x18346500;
fbs[1].bottom = (u8 *)0x18446500;
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
invokeArm11Function(SETUP_FRAMEBUFFERS);
}
void initScreens(void)
{
static bool needToSetup = true;
if(needToSetup)
{
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
invokeArm11Function(SETUP_FRAMEBUFFERS);
if(!ARESCREENSINITIALIZED)
{
initScreensSequence();
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
invokeArm11Function(INIT_SCREENS);
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
else updateBrightness(MULTICONFIG(BRIGHTNESS));
setupFramebuffers();
clearScreens(true);
needToSetup = false;
}
clearScreens(false);
clearScreens(true);
swapFramebuffers(false);
}

View File

@@ -53,7 +53,7 @@ struct fb {
typedef enum
{
INIT_SCREENS_SEQUENCE = 0,
INIT_SCREENS = 0,
SETUP_FRAMEBUFFERS,
CLEAR_SCREENS,
SWAP_FRAMEBUFFERS,
@@ -64,7 +64,6 @@ typedef enum
} Arm11Operation;
extern struct fb fbs[2];
extern CfgData configData;
void prepareArm11ForFirmlaunch(void);
void deinitScreens(void);

Some files were not shown because too many files have changed in this diff Show More