Compare commits

...

133 Commits

Author SHA1 Message Date
Beatrice
0bce9523a2 Update 'README.md' 2022-05-31 00:48:33 +02:00
Lorenzo Dellacà
884b4a4e4a removed exception dump parser, moved to new repo: https://github.com/LumaTeam/luma3ds_exception_dump_parser 2020-07-25 13:49:44 +02:00
Lorenzo Dellacà
08110cb125 added "-lm" flag 2020-07-22 22:15:42 +02:00
Lorenzo Dellacà
fd8dd82a8d fixed various build errors 2020-07-22 22:11:32 +02:00
Lorenzo Dellacà
47b5466a6e Merge branch 'master' into 3gx-master
* master:
  rosalina: work around gsp bug
  fix typo in screen filters menu
2020-07-22 19:27:49 +02:00
Lorenzo Dellacà
15342b5030 Merge branch 'master' into 3gx-master
* master:
  removed duplicate include
2020-07-22 19:24:15 +02:00
Lorenzo Dellacà
832c215a2d removed duplicate include 2020-07-22 19:21:59 +02:00
Lorenzo Dellacà
979c59d6f2 Merge commit 'bb07a7334f064c9512bd7e387dab1b9ef9e228cd' into 3gx-master
* commit 'bb07a7334f064c9512bd7e387dab1b9ef9e228cd': (23 commits)
  update gitignore and makefile
  rosalina: ndm + shutdown issue workaround
  rosalina: ndm doesn't exist on SAFE_FIRM
  Update bug-report.md, etc
  rosalina: forgot float suffix in luminance.c
  rosalina: display min/max luminance
  hbloader: allow homebrew to write to the shared config page
  rosalina: minor menu changes
  rosalina/sm: properly interact with ndm
  k11ext: refactor ndm:u workaround
  k11ext: fix oops
  rosalina: properly rewrite luminance-setting menu, etc.
  sysmodules: use libctru configmem defs
  Fix release building (#1454)
  sysmodules: introduce "luma shared config", rewrite ndmu workaround
  rosalina: autoclose menu on sleep mode/shell closed to prevent lockup
  rosalina: prevent disconnect when shell is closed
  rosalina: properly restore screen filters when lid is reopened
  rosalina: prevent sleep mode entry if debugger/input redir is enabled to prevent lockup
  Separate exception dump parser in another repo, add boot.3dsx to release command
  ...

# Conflicts:
#	.gitignore
#	exception_dump_parser/luma3ds_exception_dump_parser/__main__.py
#	sysmodules/rosalina/source/input_redirection.c
#	sysmodules/rosalina/source/menu.c
2020-07-21 11:27:18 +02:00
TuxSH
738a242e3c rosalina: work around gsp bug 2020-07-17 13:50:00 +01:00
TuxSH
5fd6dc6dd4 Merge pull request #1459 from iomintz/patch-1
fix typo in screen filters menu
2020-07-17 11:40:12 +01:00
iomintz
3fd9cacb6d fix typo in screen filters menu
Ember is 1200K, not 2700K.
2020-07-17 08:56:10 +00:00
TuxSH
bb07a7334f update gitignore and makefile 2020-07-16 18:06:14 +01:00
TuxSH
748b771618 rosalina: ndm + shutdown issue workaround 2020-07-16 17:55:31 +01:00
TuxSH
d6e72080d9 rosalina: ndm doesn't exist on SAFE_FIRM 2020-07-16 16:56:59 +01:00
TuxSH
70109fed2c Update bug-report.md, etc 2020-07-16 16:25:56 +01:00
TuxSH
cf36d21daf rosalina: forgot float suffix in luminance.c 2020-07-16 01:24:22 +01:00
TuxSH
781cd85b00 rosalina: display min/max luminance 2020-07-16 00:50:05 +01:00
TuxSH
514537a983 hbloader: allow homebrew to write to the shared config page 2020-07-15 23:04:35 +01:00
TuxSH
184f4587fb rosalina: minor menu changes 2020-07-15 22:24:08 +01:00
TuxSH
e096aaabc4 rosalina/sm: properly interact with ndm 2020-07-15 18:57:53 +01:00
TuxSH
ba26ae0f1c k11ext: refactor ndm:u workaround 2020-07-15 17:33:47 +01:00
TuxSH
786adf0268 k11ext: fix oops 2020-07-15 00:56:25 +01:00
TuxSH
2af05220c2 rosalina: properly rewrite luminance-setting menu, etc. 2020-07-14 22:10:13 +01:00
TuxSH
362c4ffff1 sysmodules: use libctru configmem defs 2020-07-12 21:26:02 +01:00
Death Mask Salesman
95fd4e763b Fix release building (#1454)
`boot.3dsx` is downloaded from a static URL via `curl`.

Fixes #1453
2020-07-12 19:39:03 +01:00
TuxSH
768e587b76 sysmodules: introduce "luma shared config", rewrite ndmu workaround 2020-07-12 19:36:18 +01:00
TuxSH
e3bb1c1b63 rosalina: autoclose menu on sleep mode/shell closed to prevent lockup 2020-07-11 22:04:13 +01:00
TuxSH
4c01bb453c rosalina: prevent disconnect when shell is closed
Fuck ndm, fuck StreetPass
2020-07-11 21:39:36 +01:00
TuxSH
dc67d438dc rosalina: properly restore screen filters when lid is reopened 2020-07-10 22:58:07 +01:00
TuxSH
2d58ec4c86 rosalina: prevent sleep mode entry if debugger/input redir is enabled to prevent lockup 2020-07-09 22:20:29 +01:00
TuxSH
555286ea47 Separate exception dump parser in another repo, add boot.3dsx to release command
https://github.com/LumaTeam/luma3ds_exception_dump_parser
2020-07-09 19:52:55 +01:00
TuxSH
b17eb66d55 rosalina inputredir: Use ir patch from @Nanquitas ; also refactor the code
Fixes #1428, #1438 (I think)
2020-07-08 22:08:57 +01:00
Lorenzo Dellacà
5670062a0f updated .gitignore 2020-07-08 00:44:26 +02:00
TuxSH
9ca52054cf rosalina: bump FS priority 2020-07-07 23:27:26 +01:00
TuxSH
991f51831d kext: add hid/ir thread locking 2020-07-07 23:27:15 +01:00
Lorenzo Dellacà
53ab41e6d0 fixed ARM "undefined instruction" kernel panic when closing games 2020-07-07 00:16:45 +02:00
Lorenzo Dellacà
1176fa8f28 Merge branch 'master' into 3gx-master
* master:
  Change screen filters presets (adding more) menu & print CCT. Fixes #1442.
  rosalina: implement 800px top-screen screenshot, etc. Fixes #1443

# Conflicts:
#	sysmodules/rosalina/source/draw.c
2020-07-06 20:20:27 +02:00
TuxSH
e69f89a0d4 Change screen filters presets (adding more) menu & print CCT. Fixes #1442.
Most new presets come from 8bitwonder
2020-07-05 20:54:27 +01:00
TuxSH
9411a8c186 rosalina: implement 800px top-screen screenshot, etc. Fixes #1443 2020-07-05 18:44:41 +01:00
Lorenzo Dellacà
aa577d0e39 Update README.md 2020-07-04 14:43:01 +02:00
Lorenzo Dellacà
241dd35000 Update README.md 2020-07-04 14:33:01 +02:00
Lorenzo Dellacà
ca48641a7e fix make error 2020-07-04 11:51:15 +02:00
Lorenzo Dellacà
1fce207bcf trying to fix crashes (cheats, closing games) 2020-07-04 11:49:36 +02:00
Lorenzo Dellacà
c58cb2d916 credits update 2020-07-04 11:30:08 +02:00
Lorenzo Dellacà
d734e36a3a added debug info, udpated makefile to show beta version 2020-07-04 04:16:55 +02:00
Lorenzo Dellacà
28d84f30bb no message 2020-07-04 03:49:02 +02:00
Lorenzo Dellacà
0bb56031d7 no message 2020-07-04 03:38:28 +02:00
Lorenzo Dellacà
cc9977774e fix compile errors 2020-07-04 03:30:15 +02:00
Lorenzo Dellacà
a39053c3c3 Merge remote-tracking branch 'origin/master'
* origin/master: (98 commits)
  rosalina: fix for latest libctru changes
  pm: fix critical bugs where 1.0(?) titles not in the list have scheduling mode misconfigured
  loader: revert to use the NS patch due to a Nintendo bug: https://www.3dbrew.org/wiki/NCCH/Extended_Header#Flag1
  loader: replace NS N3DS CPU patch with exheader override, fix overriding exheader with homebrew
  rosalina: ntp: use PTMSYSM_SetRtcTime
  revert the memory map to the old one (mostly)
  fix module loading
  kext: fix outer memory cacheability on newer versions
  so bascially rosalina's image...
  rosalina: add hidden debug info menu
  rosalina: refactor menu handling
  rosalina: rephrase brightness warning
  rosalina: add brightness control menu
  rosalina/pm: remove fs patch, use pm instead
  rosalina: cleanup variable names
  rosalina: reorder menus
  Fix latest commit
  rosalina menu: add scrolling, cpad and inputredir support (note: no ZL/ZR due to technical reasons)
  stuff
  newlib...
  ...

# Conflicts:
#	k11_extension/source/main.c
#	k11_extension/source/svc/UnmapProcessMemoryEx.c
#	sysmodules/rosalina/Makefile
#	sysmodules/rosalina/include/menu.h
#	sysmodules/rosalina/include/utils.h
#	sysmodules/rosalina/source/errdisp.c
#	sysmodules/rosalina/source/main.c
#	sysmodules/rosalina/source/menu.c
#	sysmodules/rosalina/source/menus.c
2020-07-04 02:43:27 +02:00
TuxSH
dc4de4ce6f rosalina: fix for latest libctru changes 2020-06-26 09:43:42 +01:00
TuxSH
4e12453fff pm: fix critical bugs where 1.0(?) titles not in the list have scheduling mode misconfigured
Also fix the comments.
Thanks @fincs
2020-06-26 01:04:12 +01:00
Aurora Wright
3a0418e279 loader: revert to use the NS patch due to a Nintendo bug: https://www.3dbrew.org/wiki/NCCH/Extended_Header#Flag1 2020-05-29 23:31:05 +02:00
Aurora Wright
1899bf377b loader: replace NS N3DS CPU patch with exheader override, fix overriding exheader with homebrew 2020-05-29 20:57:05 +02:00
TuxSH
0471002d4c rosalina: ntp: use PTMSYSM_SetRtcTime 2020-05-18 22:43:00 +01:00
TuxSH
704e08dc23 revert the memory map to the old one (mostly) 2020-05-18 22:15:34 +01:00
TuxSH
905837468c fix module loading 2020-05-18 21:05:36 +01:00
TuxSH
19d95782e1 kext: fix outer memory cacheability on newer versions 2020-05-18 20:48:54 +01:00
TuxSH
adda19ecb2 so bascially rosalina's image...
was in BASE (hardcoded by kernel) while its heaps were in SYSTEM. Fix this; also put the kext where BASE was.
2020-05-18 01:15:44 +01:00
TuxSH
b02d0346fd rosalina: add hidden debug info menu 2020-05-17 22:48:26 +01:00
TuxSH
9097276a06 rosalina: refactor menu handling 2020-05-17 16:42:44 +01:00
TuxSH
e99ab11c6f rosalina: rephrase brightness warning 2020-05-16 18:31:30 +01:00
TuxSH
a564d8536a rosalina: add brightness control menu 2020-05-16 02:37:47 +01:00
TuxSH
a21eee9207 rosalina/pm: remove fs patch, use pm instead 2020-05-15 22:15:55 +01:00
TuxSH
71cddef78f rosalina: cleanup variable names 2020-05-15 20:00:13 +01:00
TuxSH
9ae913064c rosalina: reorder menus 2020-05-15 02:29:17 +01:00
TuxSH
a2313d1c03 Fix latest commit 2020-05-15 02:06:52 +01:00
TuxSH
22db3445a0 rosalina menu: add scrolling, cpad and inputredir support (note: no ZL/ZR due to technical reasons) 2020-05-14 21:05:27 +01:00
TuxSH
6417720d7d stuff 2020-05-11 10:25:33 +01:00
TuxSH
8b10906d90 newlib... 2020-05-10 18:54:51 +01:00
TuxSH
0c55324d11 rosalina shutdown/reboot: fix a few things 2020-05-10 15:35:39 +01:00
TuxSH
0b4fdc6e66 Revert "Shutdown via rosalina menu is now much faster; similar thing for reboot"
This reverts commit 9942e8b299.
2020-05-10 15:08:13 +01:00
TuxSH
d3e62df769 rosalina: implement dirty hb chainload 2020-05-10 02:58:21 +01:00
Aurora
04bd881cfa Update README.md
Reflect move to the Organization
2020-05-09 20:07:07 +02:00
TuxSH
96799455cb rosalina: allow booting homebrew w/o having to reboot if using a different memory mode 2020-05-09 02:25:33 +01:00
TuxSH
814792eb91 pm: fix handling of PMLAUNCHFLAG_FORCE_USE_O3DS_MAX_APP_MEM 2020-05-09 01:37:09 +01:00
TuxSH
2834bae318 rosalina screenshots: improve conversion time by another 10% 2020-05-08 20:51:41 +01:00
TuxSH
037fae99d6 rosalina: use kernel cached RAM mapping for pixel conversion
Conversion time goes down by 90% with this
2020-05-08 20:20:51 +01:00
TuxSH
49c8888948 rosalina: put screenshot loop inside same TU 2020-05-08 18:19:17 +01:00
TuxSH
1875556f81 Merge pull request #1417 from mtheall/master
Add printf attrtibute to Draw_DrawFormattedString
2020-05-08 16:52:52 +01:00
TuxSH
00850bf691 rosalina: fast screenshots (10s -> 0.3s on my end) 2020-05-08 16:44:30 +01:00
TuxSH
09fd199487 rosalina: Dynamically alloc/free fb cache, exempt rosalina from reslimiting 2020-05-08 01:17:46 +01:00
Michael Theall
32c53578e0 Add printf attrtibute to Draw_DrawFormattedString 2020-05-06 22:34:09 -05:00
TuxSH
0da90f61fc Fix ODR bugs 2020-05-05 18:13:32 +01:00
TuxSH
9942e8b299 Shutdown via rosalina menu is now much faster; similar thing for reboot 2020-05-05 02:01:30 +01:00
TuxSH
daaeb97834 Don't do firmlaunch patches on safe_firm (because of USM) 2020-05-03 01:53:35 +01:00
TuxSH
92da214066 loader: add dsp patch for safe_firm 2020-05-02 23:50:04 +01:00
TuxSH
0f05dd5c0a Revert "rosalina draw.c: remove wait for cmd, gpu processing engine is prone to crashes"
This reverts commit 7dc2b7123b.
2020-05-02 23:36:27 +01:00
TuxSH
166bdbeb7d Add option to run rosalina on N3DS SAFE_FIRM.
Also enables a qtm error bypass
2020-05-02 23:32:21 +01:00
TuxSH
7dc2b7123b rosalina draw.c: remove wait for cmd, gpu processing engine is prone to crashes 2020-05-02 22:38:03 +01:00
TuxSH
3d0ec9b785 Make 3dsx feature compatible with n3ds safe_firm, HOWEVER apps that actually use the GPU won't work 2020-05-02 22:37:15 +01:00
TuxSH
85cfa5cba6 loader: enable secureinfo patch on safe_firm 2020-05-02 18:26:58 +01:00
TuxSH
fdc1eaa16c pm: quick safe_firm fixes 2020-05-02 18:08:24 +01:00
TuxSH
d4dcf1a3e9 k11ext: support SAFE_FIRM in rosalinaThreadLockPredicate 2020-05-02 14:44:39 +01:00
TuxSH
43fd137d55 Use kernel version minor 2020-05-02 12:35:44 +01:00
TuxSH
6931eadc34 update bug report template again 2020-04-29 23:09:20 +01:00
TuxSH
3143e7e1d0 ntp: stop overwriting rtc hwcal cfg backup 2020-04-29 20:18:02 +01:00
TuxSH
d03396d272 pxi: stop putting thread structures on the stack 2020-04-29 16:58:52 +01:00
TuxSH
c8aa2e8a89 change notification 0x1001=>0x2000 2020-03-28 10:58:36 +00:00
TuxSH
c7a3a0278c add quick luma detection getinfo 2020-04-28 10:42:30 +01:00
TuxSH
5924f60d06 gbd: fix address lookup limit on lower fw 2020-04-28 02:45:48 +01:00
TuxSH
cd68b66c03 change kext base address to 0x70000000 2020-04-28 02:39:57 +01:00
TuxSH
44cd3928fb rosalina & pm: properly shutdown when debugger, input redir (but not both) and force connection are enabled 2020-04-28 01:31:29 +01:00
TuxSH
8c54613e44 rosalina/sysconfig: fix handling of disconnected routers in wifi forcing + handle leak 2020-04-28 00:05:55 +01:00
TuxSH
7dfa83b8c0 rosalina: fix gdb/input redir hanging if no internet & fix recovering from failures 2020-04-27 21:58:40 +01:00
TuxSH
b551061264 rosalina/sysconfig: fix wifi forcing, including a regression from v10.1.1 2020-04-27 20:00:41 +01:00
TuxSH
3e228c33c9 here we go again 2020-04-27 18:11:42 +01:00
TuxSH
2b23be8f44 rosalina/cheats: fix v10.1.1 regression where cheats were not working at all. Fixes #1404 2020-04-27 17:59:51 +01:00
TuxSH
ced78cb072 use -wrap for exit 2020-04-27 01:07:57 +01:00
TuxSH
fb17850c3d Update issue template 2020-04-27 01:00:01 +01:00
TuxSH
7f7c4852cc hbloader: raise the maximum time share APT_SetAppCpuTimeLimit can set from 30% to 89%...
... now that we understand both PM and the kernel better.

89% is the maximum value supported for this preemption mode.
2020-04-27 00:57:00 +01:00
TuxSH
f334e3b951 loader/pm: move "force init SD" code to pm. Greatly reduces the number of Arm9 svcBreak with 0xC8804465 2020-04-27 00:47:16 +01:00
TuxSH
9d62995799 rosalina: make the task runner thread actually exit 2020-04-26 21:37:18 +01:00
TuxSH
1d8b793cf7 rosalina: don't keep an ac:u handle. Partially fixes the shutdown issue 2020-04-26 20:55:52 +01:00
TuxSH
33431cb939 pm/kext: make pm terminate Rosalina, removing the need for a dodgy kext hook 2020-04-26 20:33:24 +01:00
TuxSH
e677e0142c rosalina: lower thread prios & make task runner take termination into account 2020-04-26 19:36:59 +01:00
TuxSH
b313a4aa2f rosalina: remove all remaining refs to __syscalls (which we don't init) 2020-04-26 12:07:17 +01:00
TuxSH
37c5c6f049 cheats: don't use rand() 2020-04-26 11:47:15 +01:00
TuxSH
a6d92ed8fe cheats: use pm:dbg new commands to get the application's title ID 2020-04-26 11:27:55 +01:00
TuxSH
eb37ac4142 redefine exit methods for sysmodules. Partially fixes the shutdown issue 2020-04-26 01:50:47 +01:00
TuxSH
a0d4b96915 Fix stack overflow in ProcessListMenu_DumpMemory 2020-04-25 22:48:31 +01:00
PabloMK7
f1b787c7d9 Merge pull request #3 from AuroraWright/master
Merge 10.0.1
2019-07-06 09:37:41 +02:00
PabloMK7
6b13b5d06b Merge branch 'AuroraWright-master' 2019-06-29 23:35:07 +02:00
PabloMK7
9705083b65 Fix conflicting files 2019-06-29 23:34:45 +02:00
PabloMK7
2423d1802e Add plgldr string to config menu 2019-06-29 17:16:17 +02:00
PabloMK7
0b68baa0dd Merge branch 'Nanquitas-master' 2019-06-29 16:26:26 +02:00
PabloMK7
8168d2c2f9 Manually merge files 2019-06-29 16:26:03 +02:00
Nanquitas
4b341e039a Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2018-11-15 13:49:35 +01:00
Nanquitas
1ae01c2406 GDB: add 'catchsvc' command to catch svc with IDA
Usage:
   - 'catchsvc 0' : Don't catch svcs
   - 'catchsvc 1' : Catch all svcs
   - 'catchsvc 1;19;24;32;' : Only catch svc 0x19, svc 0x24 and svc 0x32
2018-11-15 13:44:45 +01:00
Nanquitas
2182742708 Implement plugin loader 2018-11-15 13:38:19 +01:00
Nanquitas
2520079536 Increase code dump on exception 2018-08-04 16:22:16 +02:00
Aurora Wright
d7095ce37d Fix patchKernel9Panic on 11.8 NATIVE_FIRM (pattern tested down to 3.0) 2018-08-04 16:11:14 +02:00
Nanquitas
0a87e41c66 socAccept: Fix an omitted comment, which masked a condition 2018-08-04 16:10:35 +02:00
Nanquitas
bec8daf028 Fix sleep issue (freeze) when InputRedirection is enabled 2018-06-23 23:06:18 +02:00
138 changed files with 5716 additions and 1777 deletions

View File

@@ -7,13 +7,13 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
-- THIS IS NOT A SUPPORT FORUM! For support go here:
-- Nintendo Homebrew: https://discord.gg/MjzatM8
--
-- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752
-- Rosalina feature requests go here: https://github.com/LumaTeam/Luma3DS/issues/752
--
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
-- Also check the Wiki (https://github.com/LumaTeam/Luma3DS/wiki) before making an issue.
--
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.hacks.guide/troubleshooting
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: use https://github.com/MechanicalDragon0687/TWLFix-CFW and update your system.
-- If you're using an emu/redNAND try installing anything on it to sysNAND.
-- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
-- Please make sure to read "Enable game patching" https://github.com/LumaTeam/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
--
-- Luma updaters that don't support Boot9Strap/Sighax won't work.
-- This is due to support for non-B9S/Sighax entrypoints being dropped.
@@ -21,7 +21,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
-- Please fill in the placeholders.-->
**System model:**
[e.g. 2DS, New 3DS, Old 3DS]
[New 2DS XL, New 3DS XL, New 3DS, Old 2DS, Old 3DS XL, Old 3DS]
**SysNAND version (+emu/redNAND version if applicable):**
@@ -34,7 +34,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
**Luma3DS version:**
[e.g. v10.0.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c]
[e.g. v10.2 stable or if using non-releases specify the commit like this https://github.com/LumaTeam/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c]
**Luma3DS configuration/options:**
@@ -50,7 +50,7 @@ Splash duration: ( )
PIN lock: ( )
New 3DS CPU: ( )
<!--This option is only available for New 3DS/2DS.-->
<!--This option is only available on New 3DS (XL)/New 2DS XL.-->
--
@@ -70,12 +70,13 @@ Show NAND or user string in System Settings: ( )
Show GBA boot screen in patched AGB_FIRM: ( )
Patch Arm9 access: ( )
Set developer UNITINFO: ( )
Disable Arm11 exception handlers: ( )
Enable Rosalina on SAFE_FIRM: ( )
<!--This option is only available on New 3DS (XL)/New 2DS XL.-->
--

4
.gitignore vendored
View File

@@ -13,8 +13,12 @@ exceptions/arm11/build
*.d
*.elf
*.cxi
*.3dsx
.DS_Store
*.dmp
.project
.cproject
.settings
.idea/
Luma3DS*.zip

View File

@@ -15,9 +15,10 @@ release: $(NAME)$(REVISION).zip
clean:
@$(foreach dir, $(SUBFOLDERS), $(MAKE) -C $(dir) clean &&) true
@rm -rf *.firm *.zip
@rm -rf *.firm *.zip *.3dsx
$(NAME)$(REVISION).zip: boot.firm exception_dump_parser
# boot.3dsx comes from https://github.com/fincs/new-hbmenu/releases
$(NAME)$(REVISION).zip: boot.firm boot.3dsx
@zip -r $@ $^ -x "*.DS_Store*" "*__MACOSX*"
boot.firm: $(SUBFOLDERS)
@@ -25,5 +26,9 @@ boot.firm: $(SUBFOLDERS)
-A 0x18180000 -C XDMA XDMA NDMA XDMA
@echo built... $(notdir $@)
boot.3dsx:
@curl -sSL "https://github.com/fincs/new-hbmenu/releases/latest/download/boot.3dsx" -o "$@"
@echo downloaded... $(notdir $@)
$(SUBFOLDERS):
@$(MAKE) -C $@ all

View File

@@ -1,13 +1,52 @@
# Luma3DS
*Noob-proof (N)3DS "Custom Firmware"*
# Luma3DS-3GX Plugin Edition
*Noob-proof (N)3DS "Custom Firmware", with 3GX plugins support*
### What it is
### 3GX Plugin Edition
This edition of **Luma3DS** allows the loading of **.3GX plugins** in Luma3DS, which are otherwise officially unsupported.
**Warning!** This was a quick, unstable hotfix I published to get things to work while waiting for official updates. The official firmware has now been updated to include 3gx plugins too. Do NOT use this fork.
#
### How to install this Edition
1. download the latest `boot.firm` from [the releases page](https://github.com/mind-overflow/Luma3DS-3GX/releases/latest)
2. put the downloaded `boot.firm` file in the `root` directory of your SD card (`sd:/boot.firm`), overwriting the official Luma3DS `boot.firm`.
3. (re)boot your 3DS, and when prompted, enable:
- "Enable game patching"
- "Show NAND or user string in System Settings"
4. press `START` and let your 3DS boot.
You successfully installed the 3GX Plugin Loader! Now, proceed to the next step to learn how to install and enable 3GX plugins.
#
### How to install 3GX plugins
Plugins have to be installed in the `sd:/luma/plugins` folder.
Usually, you need to put your specific plugin in the `<TITLEID>` subdirectory, eg: `sd:/luma/plugins/<TITLEID>/<filename>.3gx`.
However, a `default.3gx` plugin can also be placed in the main `sd:/luma/plugins` directory: `sd:/luma/plugins/default.3gx`.
So:
``` yaml
sd:/luma/plugins/default.3gx # will be loaded for all games, low priority
sd:/luma/plugins/<TITLEID>/<filename>.3gx # will only be loaded for the specified title, high priority
```
Now you know how to install 3GX plugins! Proceed to the next step to learn how how to enable 3GX plugins.
#
### How to enable 3GX plugins
1. when booted, press `L + D-Pad Down + Select` to open the Rosalina menu.
2. Press `D-Pad Down` again until `Plugin Loader`, is selected, then press `A` and set it to `[Enabled]`.
Done! You learned to install the 3GX Plugin loader, install 3GX Plugins and enable them. Now, simply launch the game you want to play and press `SELECT` to open up the 3GX menu!
#
### Luma3DS introduction
**Luma3DS** is a program to patch the system software of (New) Nintendo (2)3DS handheld consoles "on the fly", adding features such as per-game language settings, debugging capabilities for developers, and removing restrictions enforced by Nintendo such as the region lock.
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
To use it, you will need a console capable of running homebrew software on the Arm9 processor. We recommend [Plailect's guide](https://3ds.hacks.guide/) for details on how to get your system ready.
To use it, you will need a console capable of running homebrew software on the Arm9 processor.
Since v8.0, Luma3DS has its own in-game menu, triggerable by <kbd>L+Down+Select</kbd> (see the [release notes](https://github.com/AuroraWright/Luma3DS/releases/tag/v8.0)).
Since v8.0, Luma3DS has its own in-game menu, triggerable by <kbd>L+Down+Select</kbd> (see the [release notes](https://github.com/LumaTeam/Luma3DS/releases/tag/v8.0)).
#
### Compiling
@@ -16,18 +55,18 @@ Since v8.0, Luma3DS has its own in-game menu, triggerable by <kbd>L+Down+Select<
2. [makerom](https://github.com/jakcron/Project_CTR) in PATH
3. [firmtool](https://github.com/TuxSH/firmtool)
4. Up-to-date devkitARM+libctru
1. Clone the repository with `git clone https://github.com/AuroraWright/Luma3DS.git`
1. Clone the repository with `git clone https://github.com/mind-overflow/Luma3DS-3GX.git`
2. Run `make`.
The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap.
#
### Setup / Usage / Features
See https://github.com/AuroraWright/Luma3DS/wiki
See https://github.com/LumaTeam/Luma3DS/wiki
#
### Credits
See https://github.com/AuroraWright/Luma3DS/wiki/Credits
See https://github.com/LumaTeam/Luma3DS/wiki/Credits
#
### Licensing

View File

@@ -158,7 +158,7 @@ $(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
memory.o strings.o: CFLAGS += -O3
config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION) configuration\""
config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION)_3gx_beta configuration\""
patches.o: CFLAGS += -DVERSION_MAJOR="$(VERSION_MAJOR)" -DVERSION_MINOR="$(VERSION_MINOR)"\
-DVERSION_BUILD="$(VERSION_BUILD)" -DISRELEASE="$(IS_RELEASE)" -DCOMMIT_HASH="0x$(COMMIT)"
#---------------------------------------------------------------------------------

View File

@@ -95,6 +95,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Set developer UNITINFO",
"( ) Disable Arm11 exception handlers",
"( ) Enable Rosalina on SAFE_FIRM",
};
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
@@ -193,7 +194,16 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"Note: Disabling the exception handlers\n"
"will disqualify you from submitting\n"
"issues or bug reports to the Luma3DS\n"
"GitHub repository!"
"GitHub repository!",
"Enables Rosalina, the kernel ext.\n"
"and sysmodule reimplementations on\n"
"SAFE_FIRM (New 3DS only).\n\n"
"Also suppresses QTM error 0xF96183FE,\n"
"allowing to use 8.1-11.3 N3DS on\n"
"New 2DS XL consoles.\n\n"
"Only select this if you know what you\n"
"are doing!",
};
FirmwareSource nandType = FIRMWARE_SYSNAND;
@@ -229,7 +239,8 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
{ .visible = true },
{ .visible = true },
{ .visible = true },
{ .visible = true }
{ .visible = true },
{ .visible = ISN3DS },
};
//Calculate the amount of the various kinds of options and pre-select the first single one

View File

@@ -34,7 +34,7 @@
#define CONFIG_FILE "config.bin"
#define CONFIG_VERSIONMAJOR 2
#define CONFIG_VERSIONMINOR 3
#define CONFIG_VERSIONMINOR 4
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
@@ -60,7 +60,8 @@ enum singleOptions
PATCHVERSTRING,
SHOWGBABOOT,
PATCHUNITINFO,
DISABLEARM11EXCHANDLERS
DISABLEARM11EXCHANDLERS,
ENABLESAFEFIRMROSALINA,
};
typedef enum ConfigurationStatus

View File

@@ -34,6 +34,8 @@
#include "buttons.h"
#include "arm9_exception_handlers.h"
// See https://github.com/LumaTeam/luma3ds_exception_dump_parser
void installArm9Handlers(void)
{
vu32 *dstVeneers = (vu32 *)0x08000000;

View File

@@ -278,7 +278,8 @@ static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool lo
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
}
if(firmType == NATIVE_FIRM && (ISN3DS || firmVersion >= 0x1D))
// SAFE_FIRM only for N3DS and only if ENABLESAFEFIRMROSALINA is on
if((firmType == NATIVE_FIRM || firmType == SAFE_FIRM) && (ISN3DS || firmVersion >= 0x1D))
{
//2) Merge that info with our own modules'
for(u8 *src = (u8 *)0x18180000; memcmp(((Cxi *)src)->ncch.magic, "NCCH", 4) == 0; src += srcModuleSize)
@@ -303,7 +304,9 @@ static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool lo
//3) Read or copy the modules
u8 *dst = firm->section[0].address;
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)
// SAFE_FIRM only for N3DS and only if ENABLESAFEFIRMROSALINA is on
u32 maxModuleSize = (firmType == NATIVE_FIRM || firmType == SAFE_FIRM) ? 0x80000 : 0x600000;
for(u32 i = 0, dstModuleSize; i < nbModules; i++, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
{
if(loadFromStorage)
{
@@ -335,7 +338,7 @@ static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool lo
memcpy(dst, moduleList[i].src, dstModuleSize);
}
//4) Patch NATIVE_FIRM if necessary
//4) Patch NATIVE_FIRM/SAFE_FIRM (N3DS) if necessary
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)
@@ -522,6 +525,32 @@ u32 patch1x2xNativeAndSafeFirm(void)
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
if(ISN3DS && CONFIG(ENABLESAFEFIRMROSALINA))
{
u8 *arm11Section1 = (u8 *)firm + firm->section[1].offset;
//Find the Kernel11 SVC table and handler, exceptions page and free space locations
u32 baseK11VA;
u8 *freeK11Space;
u32 *arm11SvcHandler,
*arm11ExceptionsPage,
*arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage);
ret += installK11Extension(arm11Section1, firm->section[1].size, false, baseK11VA, arm11ExceptionsPage, &freeK11Space);
ret += patchKernel11(arm11Section1, firm->section[1].size, baseK11VA, arm11SvcTable, arm11ExceptionsPage);
// Add some other patches to the mix, as we can now launch homebrew on SAFE_FIRM:
//Apply firmlaunch patches
//Or don't, this makes usm not work
//ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
ret += patchKernel9Panic(arm9Section, kernel9Size);
ret += patchP9AccessChecks(process9Offset, process9Size);
mergeSection0(NATIVE_FIRM, 0x45, false); // may change in the future
firm->section[0].size = 0;
}
return ret;
}

View File

@@ -42,6 +42,8 @@
#include "arm9_exception_handlers.h"
#include "large_patches.h"
#define K11EXT_VA 0x70000000
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{
u8 *temp = memsearch(pos, "NCCH", size, 4);
@@ -108,9 +110,12 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
struct KExtParameters
{
u32 basePA;
u32 stolenSystemMemRegionSize;
void *originalHandlers[4];
u32 L1MMUTableAddrs[4];
volatile bool done;
struct CfwInfo
{
char magic[4];
@@ -126,6 +131,7 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} info;
};
@@ -134,8 +140,9 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
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 kextTotalSize = *(u32 *)0x18000020 - K11EXT_VA;
u32 stolenSystemMemRegionSize = kextTotalSize; // no need to steal any more mem on N3DS. Currently, everything fits in BASE on O3DS too (?)
u32 dstKextPA = (ISN3DS ? 0x2E000000 : 0x26C00000) - stolenSystemMemRegionSize; // start of BASE memregion (note: linear heap ---> <--- the rest)
u32 *hookVeneers = (u32 *)*freeK11Space;
u32 relocBase = 0xFFFF0000 + (*freeK11Space - (u8 *)arm11ExceptionsPage);
@@ -143,11 +150,11 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
hookVeneers[0] = 0xE51FF004; //ldr pc, [pc, #-8+4]
hookVeneers[1] = 0x18000004;
hookVeneers[2] = 0xE51FF004;
hookVeneers[3] = 0x40000000;
hookVeneers[3] = K11EXT_VA;
hookVeneers[4] = 0xE51FF004;
hookVeneers[5] = 0x40000008;
hookVeneers[5] = K11EXT_VA + 8;
hookVeneers[6] = 0xE51FF004;
hookVeneers[7] = 0x4000000C;
hookVeneers[7] = K11EXT_VA + 0xC;
(*freeK11Space) += 32;
@@ -175,14 +182,16 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
off += 4;
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase + 24);
struct KExtParameters *p = (struct KExtParameters *)(*(u32 *)0x18000024 - 0x40000000 + 0x18000000);
struct KExtParameters *p = (struct KExtParameters *)(*(u32 *)0x18000024 - K11EXT_VA + 0x18000000);
p->basePA = dstKextPA;
p->done = false;
p->stolenSystemMemRegionSize = stolenSystemMemRegionSize;
for(u32 i = 0; i < 4; i++)
{
u32 *handlerPos = getKernel11HandlerVAPos(pos, arm11ExceptionsPage, baseK11VA, 1 + i);
p->originalHandlers[i] = (void *)*handlerPos;
*handlerPos = 0x40000010 + 4 * i;
*handlerPos = K11EXT_VA + 0x10 + 4 * i;
}
struct CfwInfo *info = &p->info;
@@ -195,6 +204,7 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
info->bootConfig = configData.bootConfig;
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
info->rosalinaFlags = configData.rosalinaFlags;
info->versionMajor = VERSION_MAJOR;
info->versionMinor = VERSION_MINOR;
info->versionBuild = VERSION_BUILD;
@@ -221,6 +231,10 @@ u32 patchKernel11(u8 *pos, u32 size, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm
u8 *ControlMemoryPos = instrPos + 8 + displ;
u32 *off;
// Patch ControlMemory bounds checks for mem mapping
for (off = (u32 *)ControlMemoryPos; *off != 0xE0E01BF5; ++off);
*off = 0;
/*
Here we replace currentProcess->processID == 1 by additionnalParameter == 1.
This patch should be generic enough to work even on firmware version 5.0.
@@ -248,14 +262,14 @@ u32 patchKernel11(u8 *pos, u32 size, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm
//Redirect enableUserExceptionHandlersForCPUExc (= true)
for(off = arm11ExceptionsPage; *off != 0x96007F9; off++);
off[1] = 0x40000028;
off[1] = K11EXT_VA + 0x28;
off = (u32 *)memsearch(pos, patternKThreadDebugReschedule, size, sizeof(patternKThreadDebugReschedule));
if(off == NULL)
return 1;
off[-5] = 0xE51FF004;
off[-4] = 0x4000002C;
off[-4] = K11EXT_VA + 0x2C;
return 0;
}
@@ -434,7 +448,7 @@ u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size)
off32 += 2;
off32[1] = off32[0] + modulesSize;
for(; *off32 != section0size; off32++);
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
*off32 = ((modulesSize + 0x1FF) >> 9) << 9;
off = memsearch(pos, modulePidPattern, size, 4);

View File

@@ -69,6 +69,7 @@ typedef struct __attribute__((packed, aligned(4)))
u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} CfgData;
typedef struct

View File

@@ -1,188 +0,0 @@
#!/usr/bin/env python
# Requires Python >= 3.2 or >= 2.7
# This file is part of Luma3DS
# Copyright (C) 2016-2020 Aurora Wright, TuxSH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
# reasonable legal notices or author attributions in that material or in the Appropriate Legal
# Notices displayed by works containing it.
__author__ = "TuxSH"
__copyright__ = "Copyright (c) 2016-2020 TuxSH"
__license__ = "GPLv3"
__version__ = "v1.2"
"""
Parses Luma3DS exception dumps
"""
import argparse
from struct import unpack_from
import os
import subprocess
# Source of hexdump: https://gist.github.com/ImmortalPC/c340564823f283fe530b
# Credits for hexdump go to the original authors
# Slightly edited by TuxSH
def hexdump(addr, src, length=16, sep='.' ):
'''
@brief Return {src} in hex dump.
@param[in] length {Int} Nb Bytes by row.
@param[in] sep {Char} For the text part, {sep} will be used for non ASCII char.
@return {Str} The hexdump
@note Full support for python2 and python3 !
'''
result = []
# Python3 support
try:
xrange(0,1)
except NameError:
xrange = range
for i in xrange(0, len(src), length):
subSrc = src[i:i+length]
hexa = ''
isMiddle = False
for h in xrange(0,len(subSrc)):
if h == length/2:
hexa += ' '
h = subSrc[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h
hexa += h+' '
hexa = hexa.strip(' ')
text = ''
for c in subSrc:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep
result.append(('%08x: %-'+str(length*(2+1)+1)+'s |%s|') % (addr + i, hexa, text))
return '\n'.join(result)
def makeRegisterLine(A, rA, B, rB):
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
faultStatusSources = {
0b1:'Alignment', 0b100:'Instruction cache maintenance operation fault',
0b1100:'External Abort on translation - First-level', 0b1110:'External Abort on translation - Second-level',
0b101:'Translation - Section', 0b111:'Translation - Page', 0b11:'Access bit - Section', 0b110:'Access bit - Page',
0b1001:'Domain - Section', 0b1011:'Domain - Page', 0b1101:'Permission - Section', 0b1111:'Permission - Page',
0b1000:'Precise External Abort', 0b10110:'Imprecise External Abort', 0b10:'Debug event'
}
def main(args=None):
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
parser.add_argument("filename")
args = parser.parse_args()
data = b""
with open(args.filename, "rb") as f: data = f.read()
if unpack_from("<2I", data) != (0xdeadc0de, 0xdeadcafe):
raise SystemExit("Invalid file format")
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
nbRegisters //= 4
if version < (1 << 16) | 2:
raise SystemExit("Incompatible format version, please use the appropriate parser.")
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
codeOffset = 40 + 4 * nbRegisters
codeDump = data[codeOffset : codeOffset + codeDumpSize]
stackOffset = codeOffset + codeDumpSize
stackDump = data[stackOffset : stackOffset + stackDumpSize]
addtionalDataOffset = stackOffset + stackDumpSize
additionalData = data[addtionalDataOffset : addtionalDataOffset + additionalDataSize]
if processor == 9: print("Processor: Arm9")
else: print("Processor: Arm11 (core {0})".format(processor >> 16))
typeDetailsStr = ""
if exceptionType == 2:
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xe12fff7e:
typeDetailsStr = " (kernel panic)"
elif instr == 0xef00003c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xdf3c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif processor != 9 and (registers[20] & 0x80000000) != 0:
typeDetailsStr = " (VFP exception)"
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
if processor == 11 and exceptionType >= 2:
xfsr = registers[18] if exceptionType == 2 else registers[17]
print("Fault status: " + faultStatusSources[xfsr & 0xf])
if additionalDataSize != 0:
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
print("\nRegister dump:\n")
for i in range(0, nbRegisters - (nbRegisters % 2), 2):
if i == 16: print("")
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
if processor == 11 and exceptionType == 3:
print("{0:<15}{1:<20}Access type: {2}".format("FAR", "{0:08x}".format(registers[19]), "Write" if registers[17] & (1 << 11) != 0 else "Read"))
thumb = registers[16] & 0x20 != 0
addr = registers[15] - codeDumpSize + (2 if thumb else 4)
print("\nCode dump:\n")
objdump_res = ""
try:
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
if os.name == "nt" and path[0] == '/':
path = ''.join((path[1], ':', path[2:]))
objdump_res = subprocess.check_output((
path, "-marm", "-b", "binary",
"--adjust-vma="+hex(addr - codeOffset), "--start-address="+hex(addr),
"--stop-address="+hex(addr + codeDumpSize), "-D", "-z", "-M",
"reg-names-std" + (",force-thumb" if thumb else ""), args.filename
)).decode("utf-8")
objdump_res = '\n'.join(objdump_res[objdump_res.find('<.data+'):].split('\n')[1:])
except: objdump_res = ""
print(objdump_res if objdump_res != "" else hexdump(addr, codeDump))
print("\nStack dump:\n")
print(hexdump(registers[13], stackDump))
if __name__ == "__main__":
main()

View File

@@ -1,13 +0,0 @@
from setuptools import setup, find_packages
setup(
name='luma3ds_exception_dump_parser',
version='1.2',
url='https://github.com/AuroraWright/Luma3DS',
author='TuxSH',
license='GPLv3',
description='Parses Luma3DS exception dumps',
install_requires=[''],
packages=find_packages(),
entry_points={'console_scripts': ['luma3ds_exception_dump_parser=luma3ds_exception_dump_parser.__main__:main']},
)

View File

@@ -33,5 +33,6 @@ enum singleOptions
PATCHVERSTRING,
SHOWGBABOOT,
PATCHUNITINFO,
DISABLEARM11EXCHANDLERS
DISABLEARM11EXCHANDLERS,
ENABLESAFEFIRMROSALINA,
};

View File

@@ -44,8 +44,12 @@ extern KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *
extern void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse);
extern Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout);
extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
extern Result (*KProcessHwInfo__QueryMemory)(KProcessHwInfo *this, MemoryInfo *memoryInfo, PageInfo *pageInfo, void *address);
extern Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages);
extern Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages);
extern Result (*KProcessHwInfo__CheckVaState)(KProcessHwInfo *hwInfo, u32 va, u32 size, u32 state, u32 perm);
extern Result (*KProcessHwInfo__GetListOfKBlockInfoForVA)(KProcessHwInfo *hwInfo, KLinkedList *list, u32 va, u32 sizeInPage);
extern Result (*KProcessHwInfo__MapListOfKBlockInfo)(KProcessHwInfo *this, u32 va, KLinkedList *list, u32 state, u32 perm, u32 sbz);
extern Result (*KEvent__Clear)(KEvent *this);
extern void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this);
extern void (*KObjectMutex__ErrorOccured)(void);
@@ -53,8 +57,11 @@ extern void (*KObjectMutex__ErrorOccured)(void);
extern void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask);
extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
extern void (*KLinkedList_KBlockInfo__Clear)(KLinkedList *list);
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
extern void (*SleepThread)(s64 ns);
extern Result (*CreateEvent)(Handle *out, ResetType resetType);
extern Result (*CloseHandle)(Handle handle);
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
@@ -65,6 +72,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 (*SignalEvent)(Handle event);
extern Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
extern Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
@@ -129,9 +137,14 @@ typedef struct CfwInfo
u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} CfwInfo;
extern CfwInfo cfwInfo;
extern u32 kextBasePa;
extern u32 stolenSystemMemRegionSize;
extern vu32 rosalinaState;
extern bool hasStartedRosalinaNetworkFuncsOnce;
KLinkedList* KLinkedList__Initialize(KLinkedList *list);

View File

@@ -57,5 +57,4 @@ void SessionInfo_Add(KSession *session, const char *name);
void SessionInfo_Remove(KSession *session);
bool doLangEmu(Result *res, u32 *cmdbuf);
Result doPublishToProcessHook(Handle handle, u32 *cmdbuf);
bool doErrfThrowHook(u32 *cmdbuf);

View File

@@ -105,6 +105,14 @@ typedef struct ALIGN(4) KMutex
union KProcess *owner;
} KMutex;
typedef struct KAddressArbiter
{
KAutoObject autoObject;
struct KThread *first;
struct KThread *last;
union KProcess *owner;
} KAddressArbiter;
/* 92 */
typedef struct KMutexLinkedList
{
@@ -112,6 +120,30 @@ typedef struct KMutexLinkedList
KMutex *last;
} KMutexLinkedList;
enum
{
TOKEN_KAUTOOBJECT = 0,
TOKEN_KSYNCHRONIZATIONOBJECT = 1,
TOKEN_KEVENT = 0x1F,
TOKEN_KSEMAPHORE = 0x2F,
TOKEN_KTIMER = 0x35,
TOKEN_KMUTEX = 0x39,
TOKEN_KDEBUG = 0x4D,
TOKEN_KSERVERPORT = 0x55,
TOKEN_KDMAOBJECT = 0x59,
TOKEN_KCLIENTPORT = 0x65,
TOKEN_KCODESET = 0x68,
TOKEN_KSESSION = 0x70,
TOKEN_KTHREAD = 0x8D,
TOKEN_KSERVERSESSION = 0x95,
TOKEN_KADDRESSARBITER = 0x98,
TOKEN_KCLIENTSESSION = 0xA5,
TOKEN_KPORT = 0xA8,
TOKEN_KSHAREDMEMORY = 0xB0,
TOKEN_KPROCESS = 0xC5,
TOKEN_KRESOURCELIMIT = 0xC8
};
/* 45 */
typedef struct KClassToken
{
@@ -540,6 +572,20 @@ typedef struct KBlockInfo
u32 pageCount;
} KBlockInfo;
typedef struct KSharedMemory
{
KAutoObject autoObject;
KLinkedList ownedKBlockInfo;
union KProcess *owner;
u32 ownerPermissions;
u32 otherPermissions;
u8 isBlockInfoGenerated;
s8 allBlockInfoGenerated;
u8 unknown_1;
u8 unknown_2;
u32 address;
} KSharedMemory;
/* 25 */
typedef struct KMemoryBlock
{
@@ -1037,10 +1083,26 @@ typedef struct KProcess##sys\
KThread *mainThread;\
u32 interruptEnabledFlags[4];\
KProcessHandleTable handleTable;\
u8 gap234[52];\
/* Custom fields for plugin system
{ */ \
u32 customFlags; /* see KProcess_CustomFlags enum below */ \
Handle onMemoryLayoutChangeEvent;\
Handle onProcessExitEvent;\
Handle resumeProcessExitEvent;\
/* } */ \
u8 gap234[36];\
u64 unused;\
} KProcess##sys;
enum KProcess_CustomFlags
{
ForceRWXPages = 1 << 0,
SignalOnMemLayoutChanges = 1 << 1,
SignalOnExit = 1 << 2,
MemLayoutChanged = 1 << 16
};
INSTANCIATE_KPROCESS(N3DS);
INSTANCIATE_KPROCESS(O3DS8x);
INSTANCIATE_KPROCESS(O3DSPre8x);
@@ -1126,11 +1188,11 @@ typedef union KCacheMaintenanceInterruptEvent
typedef struct FcramLayout
{
void *applicationAddr;
u32 applicationAddr;
u32 applicationSize;
void *systemAddr;
u32 systemAddr;
u32 systemSize;
void *baseAddr;
u32 baseAddr;
u32 baseSize;
} FcramLayout;
@@ -1138,15 +1200,15 @@ extern bool isN3DS;
extern void *officialSVCs[0x7E];
#define KPROCESSRELATED_OFFSETOFF(classname, field) (isN3DS ? offsetof(classname##N3DS, field) :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(classname##O3DS8x, field) :\
((GET_VERSION_MINOR(kernelVersion) >= 44) ? offsetof(classname##O3DS8x, field) :\
offsetof(classname##O3DSPre8x, field)))
#define KPROCESSRELATED_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\
((GET_VERSION_MINOR(kernelVersion) >= 44) ? &(obj)->O3DS8x.field :\
&(obj)->O3DSPre8x.field))
#define KPROCESSRELATED_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\
((GET_VERSION_MINOR(kernelVersion) >= 44) ? (type *)(&(obj)->O3DS8x.field) :\
(type *)(&(obj)->O3DSPre8x.field)))
#define KPROCESS_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcess, field)
@@ -1189,7 +1251,7 @@ static inline KDebug *debugOfProcess(KProcess *process)
static inline const char *classNameOfAutoObject(KAutoObject *object)
{
const char *name;
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
if(GET_VERSION_MINOR(kernelVersion) >= 46)
{
KClassToken tok;
object->vtable->GetClassToken(&tok, object);
@@ -1205,7 +1267,7 @@ extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Ha
static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj)
{
u8 token;
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
if(GET_VERSION_MINOR(kernelVersion) >= 46)
{
KClassToken tok;
obj->vtable->GetClassToken(&tok, obj);

129
k11_extension/include/mmu.h Normal file
View File

@@ -0,0 +1,129 @@
#pragma once
#include "types.h"
#include "kernel.h"
typedef struct
{
u32 bits1_0 : 2; ///< 0b00
} Desc_TranslationFault;
typedef struct
{
u32 bits1_0 : 2; ///< 0b01
u32 sbz : 3;
u32 domain : 4;
u32 p : 1;
u32 addr : 21;
} Desc_CoarsePageTable;
typedef struct
{
u32 bits1_0 : 2; ///< 0b10
u32 b : 1;
u32 c : 1;
u32 xn : 1;
u32 domain : 4;
u32 p : 1;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 bit18 : 1; ///< 0
u32 sbz : 1;
u32 addr : 12;
} Desc_Section;
typedef struct
{
u32 bits1_0 : 2; ///< 0b10
u32 b : 1;
u32 c : 1;
u32 xn : 1;
u32 domain : 4;
u32 p : 1;
u32 ap : 2;
u32 tex : 3;
u32 sbz : 3;
u32 bit18 : 1; ///< 1
u32 sbz2 : 5;
u32 addr : 8;
} Desc_Supersection;
typedef struct
{
u32 bits1_0 : 2; ///< 0b11
} Desc_Reserved;
typedef struct
{
u32 bits1_0 : 2; ///< 0b01
u32 b : 1;
u32 c : 1;
u32 ap : 2;
u32 sbz : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 tex : 3;
u32 xn : 1;
u32 addr : 16;
} Desc_LargePage;
typedef struct
{
u32 xn : 1;
u32 bit1 : 1; ///< 1
u32 b : 1;
u32 c : 1;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 addr : 20;
} Desc_SmallPage;
typedef union
{
u32 raw;
Desc_TranslationFault translationFault;
Desc_CoarsePageTable coarsePageTable;
Desc_Section section;
Desc_Supersection supersection;
Desc_Reserved reserved;
} L1Descriptor;
typedef union
{
u32 raw;
Desc_TranslationFault translationFault;
Desc_LargePage largePage;
Desc_SmallPage smallPage;
} L2Descriptor;
typedef enum
{
Descriptor_TranslationFault,
Descriptor_CoarsePageTable,
Descriptor_Section,
Descriptor_Supersection,
Descriptor_Reserved,
Descriptor_LargePage,
Descriptor_SmallPage
} DescType;
void L1MMUTable__RWXForAll(u32 *table);
void L2MMUTable__RWXForAll(u32 *table);
u32 L1MMUTable__GetPAFromVA(u32 *table, u32 va);
u32 L2MMUTable__GetPAFromVA(u32 *table, u32 va);
u32 L1MMUTable__GetAddressUserPerm(u32 *table, u32 va);
u32 L2MMUTable__GetAddressUserPerm(u32 *table, u32 va);
void KProcessHwInfo__SetMMUTableToRWX(KProcessHwInfo *hwInfo);
u32 KProcessHwInfo__GetPAFromVA(KProcessHwInfo *hwInfo, u32 va);
u32 KProcessHwInfo__GetAddressUserPerm(KProcessHwInfo *hwInfo, u32 va);

View File

@@ -0,0 +1,21 @@
#pragma once
#include "utils.h"
#include "kernel.h"
#include "svc.h"
/// Operations for svcControlProcess
typedef enum ProcessOp
{
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
PROCESSOP_GET_ON_EXIT_EVENT,
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
PROCESSOP_SCHEDULE_THREADS,
} ProcessOp;
Result ControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);

View File

@@ -30,4 +30,5 @@
#include "kernel.h"
#include "svc.h"
Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size);
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size);
Result MapProcessMemoryExWrapper(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size);

View File

@@ -36,11 +36,12 @@ void executeFunctionOnCores(SGI0Handler_t func, u8 targetList, u8 targetListFilt
void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this);
void KThread__DebugReschedule(KThread *this, bool lock);
bool rosalinaThreadLockPredicate(KThread *thread);
bool rosalinaThreadLockPredicate(KThread *thread, u32 mask);
void rosalinaRescheduleThread(KThread *thread, bool lock);
void rosalinaLockThread(KThread *thread);
void rosalinaLockAllThreads(void);
void rosalinaUnlockAllThreads(void);
void rosalinaLockThreads(u32 mask);
void rosalinaUnlockThreads(u32 mask);
// Taken from ctrulib:
@@ -49,6 +50,11 @@ static inline void __dsb(void)
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory");
}
static inline void __dmb(void)
{
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
}
static inline void __clrex(void)
{
__asm__ __volatile__("clrex" ::: "memory");

View File

@@ -78,6 +78,15 @@ typedef s32 Result; ///< Function result.
#define SYSTEM_VERSION(major, minor, revision) \
(((major)<<24)|((minor)<<16)|((revision)<<8))
/// Retrieves the major version from a packed system version.
#define GET_VERSION_MAJOR(version) ((version) >>24)
/// Retrieves the minor version from a packed system version.
#define GET_VERSION_MINOR(version) (((version)>>16)&0xFF)
/// Retrieves the revision version from a packed system version.
#define GET_VERSION_REVISION(version) (((version)>> 8)&0xFF)
#define CUR_THREAD_HANDLE 0xFFFF8000
#define CUR_PROCESS_HANDLE 0xFFFF8001

View File

@@ -5,7 +5,7 @@ ENTRY(_start)
MEMORY
{
vram : ORIGIN = 0x18000000, LENGTH = 0x18180000 - 0x18000000 /* Up to the kernel builtins. */
main : ORIGIN = 0x40000000, LENGTH = 1M
main : ORIGIN = 0x70000000, LENGTH = 1M
}
PHDRS
@@ -15,7 +15,7 @@ PHDRS
SECTIONS
{
PROVIDE(__start__ = 0x40000000);
PROVIDE(__start__ = ORIGIN(main));
. = ABSOLUTE(__start__);
.text :

View File

@@ -28,10 +28,43 @@
#include "fatalExceptionHandlers.h"
#include "utils.h"
#include "kernel.h"
#include "memory.h"
#include "mmu.h"
#include "globals.h"
#define REG_DUMP_SIZE 4 * 23
#define CODE_DUMP_SIZE 48
#define CODE_DUMP_SIZE 96
// Return true if parameters are invalid
static bool checkExceptionHandlerValidity(KProcess *process, vu32 *threadLocalStorage)
{
if (process == NULL)
return true;
u32 stackBottom = threadLocalStorage[0x11];
u32 exceptionBuf = threadLocalStorage[0x12];
MemoryInfo memInfo;
PageInfo pageInfo;
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 perm = KProcessHwInfo__GetAddressUserPerm(hwInfo, threadLocalStorage[0x10]);
if (stackBottom != 1)
{
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)stackBottom)
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
return true;
}
if (exceptionBuf > 1)
{
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)exceptionBuf)
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
return true;
}
return (perm & MEMPERM_RX) != MEMPERM_RX;
}
bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
{
@@ -43,7 +76,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
return false;
return checkExceptionHandlerValidity(currentProcess, (vu32 *)thread->threadLocalStorage);
if(currentProcess != NULL)
{
@@ -52,7 +85,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
thread = KPROCESS_GET_RVALUE(currentProcess, mainThread);
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
return false;
return checkExceptionHandlerValidity(currentProcess, thread->threadLocalStorage);
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)
@@ -70,6 +103,7 @@ bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr)
((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz)
);
}
void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
{
ExceptionDumpHeader dumpHeader;
@@ -96,7 +130,7 @@ void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
registerDump[15] = pc;
//Dump code
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - (dumpHeader.codeDumpSize >> 1) ; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem
dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize);
//Copy register dump and code dump

View File

@@ -40,8 +40,12 @@ KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *this, H
void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse);
Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout);
Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
Result (*KProcessHwInfo__QueryMemory)(KProcessHwInfo *this, MemoryInfo *memoryInfo, PageInfo *pageInfo, void *address);
Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages);
Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages);
Result (*KProcessHwInfo__CheckVaState)(KProcessHwInfo *hwInfo, u32 va, u32 size, u32 state, u32 perm);
Result (*KProcessHwInfo__GetListOfKBlockInfoForVA)(KProcessHwInfo *hwInfo, KLinkedList *list, u32 va, u32 sizeInPage);
Result (*KProcessHwInfo__MapListOfKBlockInfo)(KProcessHwInfo *this, u32 va, KLinkedList *list, u32 state, u32 perm, u32 sbz);
Result (*KEvent__Clear)(KEvent *this);
void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this);
void (*KObjectMutex__ErrorOccured)(void);
@@ -49,8 +53,11 @@ void (*KObjectMutex__ErrorOccured)(void);
void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask);
void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
void (*KLinkedList_KBlockInfo__Clear)(KLinkedList *list);
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
void (*SleepThread)(s64 ns);
Result (*CreateEvent)(Handle *out, ResetType resetType);
Result (*CloseHandle)(Handle handle);
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
@@ -61,6 +68,7 @@ Result (*SendSyncRequest)(Handle handle);
Result (*OpenProcess)(Handle *out, u32 processId);
Result (*GetProcessId)(u32 *out, Handle process);
Result (*DebugActiveProcess)(Handle *out, u32 processId);
Result (*SignalEvent)(Handle event);
Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
@@ -102,13 +110,21 @@ u32 nbSection0Modules;
Result (*InterruptManager__MapInterrupt)(InterruptManager *manager, KBaseInterruptEvent *iEvent, u32 interruptID,
u32 coreID, u32 priority, bool disableUponReceipt, bool levelHighActive);
InterruptManager *interruptManager;
KBaseInterruptEvent *customInterruptEvent;
void (*initFPU)(void);
void (*mcuReboot)(void);
void (*coreBarrier)(void);
CfwInfo cfwInfo;
u32 kextBasePa;
u32 stolenSystemMemRegionSize;
vu32 rosalinaState;
bool hasStartedRosalinaNetworkFuncsOnce;
KLinkedList* KLinkedList__Initialize(KLinkedList *list)
{
list->size = 0;
list->nodes.first = list->nodes.last = (KLinkedListNode *)&list->nodes;
return list;
}

View File

@@ -235,48 +235,6 @@ bool doLangEmu(Result *res, u32 *cmdbuf)
return skip;
}
Result doPublishToProcessHook(Handle handle, u32 *cmdbuf)
{
Result res = 0;
u32 pid;
bool terminateRosalina = cmdbuf[1] == 0x100 && cmdbuf[2] == 0; // cmdbuf[2] to check for well-formed requests
u32 savedCmdbuf[4];
memcpy(savedCmdbuf, cmdbuf, 16);
if(!terminateRosalina || GetProcessId(&pid, cmdbuf[3]) != 0)
terminateRosalina = false;
else
{
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KProcess *process = KProcessHandleTable__ToKProcess(handleTable, cmdbuf[3]);
if((strcmp(codeSetOfProcess(process)->processName, "socket") == 0 && (rosalinaState & 2)) ||
strcmp(codeSetOfProcess(process)->processName, "pxi") == 0)
terminateRosalina = true;
else
terminateRosalina = false;
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
}
if(terminateRosalina && nbSection0Modules == 6)
{
Handle rosalinaProcessHandle;
res = OpenProcess(&rosalinaProcessHandle, 5);
if(res == 0)
{
cmdbuf[0] = cmdbuf[0];
cmdbuf[1] = 0x100;
cmdbuf[2] = 0;
cmdbuf[3] = rosalinaProcessHandle;
res = SendSyncRequest(handle);
CloseHandle(rosalinaProcessHandle);
memcpy(cmdbuf, savedCmdbuf, 16);
}
}
return SendSyncRequest(handle);
}
bool doErrfThrowHook(u32 *cmdbuf)
{
// If fatalErrorInfo->type is "card removed" or "logged", returning from ERRF:Throw is a no-op
@@ -288,24 +246,24 @@ bool doErrfThrowHook(u32 *cmdbuf)
u8 *srcerrbuf = (u8 *)r0_to_r7_r12_usr[(spsr & 0x20) ? 4 : 6];
const char *pname = codeSetOfProcess(currentCoreContext->objectContext.currentProcess)->processName;
static const struct
const struct
{
const char *name;
Result errCode;
bool enabled;
} errorCodesToIgnore[] =
{
/*
If you're getting this error, you have broken your head-tracking hardware,
and should uncomment the following line:
If you're getting this error, you may have broken your head-tracking hardware,
and you need to enable the qtm error bypass below:
*/
//{ "qtm", (Result)0xF96183FE },
{ "", 0 }, // impossible case to ensure the array has at least 1 element
{ "qtm", 0xF96183FEu, CONFIG(ENABLESAFEFIRMROSALINA)},
{ "", 0, false}, // impossible case to ensure the array has at least 1 element
};
for(u32 i = 0; i < sizeof(errorCodesToIgnore) / sizeof(errorCodesToIgnore[0]); i++)
{
if(strcmp(pname, errorCodesToIgnore[i].name) == 0 && (Result)cmdbuf[2] == errorCodesToIgnore[i].errCode)
if(errorCodesToIgnore[i].enabled && strcmp(pname, errorCodesToIgnore[i].name) == 0 && (Result)cmdbuf[2] == errorCodesToIgnore[i].errCode)
{
srcerrbuf[0] = 5;
cmdbuf[0] = 0x10040;

View File

@@ -32,22 +32,27 @@
#include "svc/ConnectToPort.h"
#include "svcHandler.h"
#define K11EXT_VA 0x70000000
struct KExtParameters
{
u32 basePA;
u32 stolenSystemMemRegionSize;
void *originalHandlers[4];
u32 L1MMUTableAddrs[4];
volatile bool done;
CfwInfo cfwInfo;
} kExtParameters = { .basePA = 0x12345678 }; // place this in .data
static ALIGN(1024) u32 L2TableFor0x40000000[256] = {0};
static ALIGN(1024) u32 g_L2Table[256] = {0};
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);
u32 *L2Table = (u32 *)((u32)L2TableFor0x40000000 - 0x40000000 + p0->basePA);
struct KExtParameters *p0 = (struct KExtParameters *)((u32)&kExtParameters - K11EXT_VA + 0x18000000);
struct KExtParameters *p = (struct KExtParameters *)((u32)&kExtParameters - K11EXT_VA + p0->basePA);
u32 *L2Table = (u32 *)((u32)g_L2Table - K11EXT_VA + p0->basePA);
if(coreId == 0)
{
@@ -56,16 +61,32 @@ void relocateAndSetupMMU(u32 coreId, u32 *L1Table)
memcpy((void *)p0->basePA, (const void *)0x18000000, __bss_start__ - __start__);
memset((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]
// Map the kernel ext at K11EXT_VA
// 4KB extended small pages:
// Outer Write-Through cached, No Allocate on Write, Buffered
// Inner Cached Write-Back Write-Allocate, Buffered
// This was changed at some point (8.0 maybe?), it was outer noncached before
for(u32 offset = 0; offset < (u32)(__end__ - __start__); offset += 0x1000)
L2Table[offset >> 12] = (p0->basePA + offset) | 0x516;
L2Table[offset >> 12] = (p0->basePA + offset) | 0x596;
p0->done = true;
// DSB, Flush Prefetch Buffer (more or less "isb")
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory");
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory");
__asm__ __volatile__ ("sev");
}
else
__asm__ __volatile__ ("wfe");
else {
do
{
__asm__ __volatile__ ("wfe");
} while(!p0->done);
// DSB, Flush Prefetch Buffer (more or less "isb")
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory");
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory");
}
// 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
@@ -76,9 +97,13 @@ void relocateAndSetupMMU(u32 coreId, u32 *L1Table)
L1Table[i + (VA >> 20)] = PA | attribs;
}
L1Table[0x40000000 >> 20] = (u32)L2Table | 1;
L1Table[K11EXT_VA >> 20] = (u32)L2Table | 1;
p->L1MMUTableAddrs[coreId] = (u32)L1Table;
// DSB, Flush Prefetch Buffer (more or less "isb")
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory");
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory");
}
void bindSGI0Hook(void)
@@ -98,11 +123,61 @@ void configHook(vu8 *cfgPage)
*isDevUnit = true; // enable debug features
}
void KProcessHwInfo__MapL1Section_Hook(void);
void KProcessHwInfo__MapL2Section_Hook(void);
static void installMmuHooks(void)
{
u32 *mapL1Section = NULL;
u32 *mapL2Section = NULL;
u32 *off;
for(off = (u32 *)officialSVCs[0x1F]; *off != 0xE1CD60F0; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE58D5000; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE58DC000; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE1A0000B; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE59D2030; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE88D1100; ++off);
mapL2Section = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(off + 1));
do
{
for (; *off != 0xE58D8000; ++off);
u32 *loc = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(++off));
if (loc != mapL2Section)
mapL1Section = loc;
} while (mapL1Section == NULL);
mapL1Section[1] = 0xE28FE004; // add lr, pc, #4
mapL1Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
mapL1Section[3] = (u32)KProcessHwInfo__MapL1Section_Hook;
mapL2Section[1] = 0xE28FE004; // add lr, pc, #4
mapL2Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
mapL2Section[3] = (u32)KProcessHwInfo__MapL2Section_Hook;
}
static void findUsefulSymbols(void)
{
u32 *off;
for(off = (u32 *)0xFFFF0000; *off != 0xE1A0D002; off++);
// Patch ERRF__DumpException
for(off = (u32 *)0xFFFF0000; *off != 0xE1A04005; ++off);
++off;
*(u32 *)PA_FROM_VA_PTR(off) = makeArmBranch(off, off + 51, false);
for(; *off != 0xE2100102; ++off);
KProcessHwInfo__QueryMemory = (Result (*)(KProcessHwInfo *, MemoryInfo *, PageInfo *, void *))decodeArmBranch(off - 1);
for(; *off != 0xE1A0D002; off++);
off += 3;
initFPU = (void (*) (void))off;
@@ -165,6 +240,18 @@ static void findUsefulSymbols(void)
for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++);
KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeArmBranch(off - 1);
for (off = (u32 *)officialSVCs[0x70]; *off != 0xE8881200 && *off != 0xE8891900; ++off);
for (off = (u32 *)decodeArmBranch(off + 1); *off != 0xE2101102; ++off);
KProcessHwInfo__CheckVaState = (Result (*)(KProcessHwInfo *, u32, u32, u32, u32))decodeArmBranch(off - 1);
for (; *off != 0xE28D1008; ++off);
KProcessHwInfo__GetListOfKBlockInfoForVA = (Result (*)(KProcessHwInfo*, KLinkedList*, u32, u32))decodeArmBranch(off + 1);
for (; *off != 0xE2000102; ++off);
KProcessHwInfo__MapListOfKBlockInfo = (Result (*)(KProcessHwInfo*, u32, KLinkedList*, u32, u32, u32))decodeArmBranch(off - 1);
for (; *off != 0xE8BD8FF0; ++off);
KLinkedList_KBlockInfo__Clear = (void (*)(KLinkedList *))decodeArmBranch(off - 6);
for(off = (u32 *)officialSVCs[0x7C]; *off != 0x03530000; off++);
KObjectMutex__WaitAndAcquire = (void (*)(KObjectMutex *))decodeArmBranch(++off);
for(; *off != 0xE320F000; off++);
@@ -210,6 +297,7 @@ static void findUsefulSymbols(void)
ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool))
decodeArmBranch((u32 *)officialSVCs[0x01] + 5);
SleepThread = (void (*)(s64))officialSVCs[0x0A];
CreateEvent = (Result (*)(Handle *, ResetType))decodeArmBranch((u32 *)officialSVCs[0x17] + 3);
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);
@@ -220,6 +308,7 @@ 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);
SignalEvent = (Result (*)(Handle event))officialSVCs[0x18];
UnmapProcessMemory = (Result (*)(Handle, void *, u32))officialSVCs[0x72];
KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1);
@@ -251,6 +340,8 @@ static void findUsefulSymbols(void)
invalidateInstructionCacheRange = (void (*)(void *, u32))off2;
}
}
installMmuHooks();
}
void main(FcramLayout *layout, KCoreContext *ctxs)
@@ -259,7 +350,11 @@ void main(FcramLayout *layout, KCoreContext *ctxs)
u32 TTBCR_;
s64 nb;
layout->systemSize -= __end__ - __start__;
cfwInfo = p->cfwInfo;
kextBasePa = p->basePA;
stolenSystemMemRegionSize = p->stolenSystemMemRegionSize;
layout->systemSize -= stolenSystemMemRegionSize;
fcramLayout = *layout;
coreCtxs = ctxs;
@@ -268,7 +363,6 @@ void main(FcramLayout *layout, KCoreContext *ctxs)
isN3DS = getNumberOfCores() == 4;
memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16);
exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20));
cfwInfo = p->cfwInfo;
memcpy(originalHandlers + 1, p->originalHandlers, 16);
void **arm11SvcTable = (void**)originalHandlers[2];
@@ -282,4 +376,8 @@ void main(FcramLayout *layout, KCoreContext *ctxs)
rosalinaState = 0;
hasStartedRosalinaNetworkFuncsOnce = false;
// DSB, Flush Prefetch Buffer (more or less "isb")
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" :: "r" (0) : "memory");
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" :: "r" (0) : "memory");
}

315
k11_extension/source/mmu.c Normal file
View File

@@ -0,0 +1,315 @@
#include "mmu.h"
#include "globals.h"
#include "utils.h"
DescType L1Descriptor__GetType(u32 descriptor)
{
L1Descriptor pdesc = {descriptor};
if (pdesc.reserved.bits1_0 == 0b00)
return Descriptor_TranslationFault;
if (pdesc.reserved.bits1_0 == 0b01)
return Descriptor_CoarsePageTable;
if (pdesc.reserved.bits1_0 == 0b10)
return pdesc.section.bit18 == 0 ? Descriptor_Section : Descriptor_Supersection;
return Descriptor_Reserved;
}
DescType L2Descriptor__GetType(u32 descriptor)
{
L2Descriptor pdesc = {descriptor};
if (pdesc.translationFault.bits1_0 == 0b01)
return Descriptor_LargePage;
if (pdesc.smallPage.bit1 == 1)
return Descriptor_SmallPage;
return Descriptor_TranslationFault;
}
void L1MMUTable__RWXForAll(u32 *table)
{
u32 *tableEnd = table + 1024;
for (; table != tableEnd; ++table)
{
L1Descriptor descriptor = {*table};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
L2MMUTable__RWXForAll(l2table);
break;
}
case Descriptor_Section:
{
descriptor.section.xn = 0;
descriptor.section.apx = 0;
descriptor.section.ap = 3;
*table = descriptor.raw;
break;
}
case Descriptor_Supersection:
{
descriptor.supersection.xn = 0;
descriptor.supersection.ap = 3;
*table = descriptor.raw;
break;
}
default:
break;
}
}
}
void L2MMUTable__RWXForAll(u32 *table)
{
u32 *tableEnd = table + 256;
for (; table != tableEnd; ++table)
{
L2Descriptor descriptor = {*table};
switch (L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
descriptor.largePage.xn = 0;
descriptor.largePage.apx = 0;
descriptor.largePage.ap = 3;
*table = descriptor.raw;
break;
}
case Descriptor_SmallPage:
{
descriptor.smallPage.xn = 0;
descriptor.smallPage.apx = 0;
descriptor.smallPage.ap = 3;
*table = descriptor.raw;
break;
}
default:
break;
}
}
}
u32 L1MMUTable__GetPAFromVA(u32 *table, u32 va)
{
u32 pa = 0;
L1Descriptor descriptor = {table[va >> 20]};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
pa = L2MMUTable__GetPAFromVA(l2table, va);
break;
}
case Descriptor_Section:
{
pa = descriptor.section.addr << 20;
pa |= (va << 12) >> 12;
break;
}
case Descriptor_Supersection:
{
pa = descriptor.supersection.addr << 24;
pa |= (va << 8) >> 8;
break;
}
default:
// VA not found
break;
}
return pa;
}
u32 L2MMUTable__GetPAFromVA(u32 *table, u32 va)
{
u32 pa = 0;
L2Descriptor descriptor = {table[(va << 12) >> 24]};
switch(L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
pa = descriptor.largePage.addr << 16;
pa |= va & 0xFFFF;
break;
}
case Descriptor_SmallPage:
{
pa = descriptor.smallPage.addr << 12;
pa |= va & 0xFFF;
break;
}
default:
break;
}
return pa;
}
u32 L1MMUTable__GetAddressUserPerm(u32 *table, u32 va)
{
u32 perm = 0;
L1Descriptor descriptor = {table[va >> 20]};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
perm = L2MMUTable__GetAddressUserPerm(l2table, va);
break;
}
case Descriptor_Section:
{
perm = descriptor.section.ap >> 1;
if (perm)
{
perm |= (!descriptor.section.apx && (descriptor.section.ap & 1)) << 1;
perm |= (!descriptor.section.xn) << 2;
}
break;
}
case Descriptor_Supersection:
{
perm = descriptor.supersection.ap >> 1;
if (perm)
{
perm |= (descriptor.supersection.ap & 1) << 1;
perm |= (!descriptor.supersection.xn) << 2;
}
break;
}
default:
// VA not found
break;
}
return perm;
}
u32 L2MMUTable__GetAddressUserPerm(u32 *table, u32 va)
{
u32 perm = 0;
L2Descriptor descriptor = {table[(va << 12) >> 24]};
switch(L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
perm = descriptor.largePage.ap >> 1;
if (perm)
{
perm |= (!descriptor.largePage.apx && (descriptor.largePage.ap & 1)) << 1;
perm |= (!descriptor.largePage.xn) << 2;
}
break;
}
case Descriptor_SmallPage:
{
perm = descriptor.smallPage.ap >> 1;
if (perm)
{
perm |= (!descriptor.smallPage.apx && (descriptor.smallPage.ap & 1)) << 1;
perm |= (!descriptor.smallPage.xn) << 2;
}
break;
}
default:
break;
}
return perm;
}
void KProcessHwInfo__SetMMUTableToRWX(KProcessHwInfo *hwInfo)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
L1MMUTable__RWXForAll(table);
KObjectMutex__Release(mutex);
}
u32 KProcessHwInfo__GetPAFromVA(KProcessHwInfo *hwInfo, u32 va)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
u32 pa = L1MMUTable__GetPAFromVA(table, va);
KObjectMutex__Release(mutex);
return pa;
}
u32 KProcessHwInfo__GetAddressUserPerm(KProcessHwInfo *hwInfo, u32 va)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
u32 perm = L1MMUTable__GetAddressUserPerm(table, va);
KObjectMutex__Release(mutex);
return perm;
}
static union
{
u32 raw;
struct
{
u32 xn : 1;
u32 unkn : 1;
u32 cb : 2;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
};
} g_rwxState;
// This function patch the permission when memory is mapped in the mmu table (rwx)
KProcessHwInfo *PatchDescriptorAccessControl(KProcessHwInfo *hwInfo, u32 **outState)
{
KProcess *process = (KProcess *)((u32)hwInfo - 0x1C);
u32 state = **outState;
u32 flags = KPROCESS_GET_RVALUE(process, customFlags);
if (flags & SignalOnMemLayoutChanges)
*KPROCESS_GET_PTR(process, customFlags) |= MemLayoutChanged;
if (!(flags & ForceRWXPages))
return hwInfo;
g_rwxState.raw = state;
g_rwxState.xn = 0;
g_rwxState.ap = 3;
g_rwxState.apx = 0;
*outState = &g_rwxState.raw;
return hwInfo;
}

View File

@@ -44,6 +44,7 @@
#include "svc/MapProcessMemoryEx.h"
#include "svc/UnmapProcessMemoryEx.h"
#include "svc/ControlService.h"
#include "svc/ControlProcess.h"
#include "svc/CopyHandle.h"
#include "svc/TranslateHandle.h"
@@ -59,13 +60,16 @@ void signalSvcEntry(u8 *pageEnd)
// Since DBGEVENT_SYSCALL_ENTRY is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!)
if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
{
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFE, svcId);
}
}
void signalSvcReturn(u8 *pageEnd)
{
u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5);
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
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
@@ -73,12 +77,19 @@ void signalSvcReturn(u8 *pageEnd)
// Since DBGEVENT_SYSCALL_RETURN is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!)
if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId);
// Signal if the memory layout of the process changed
if (flags & SignalOnMemLayoutChanges && flags & MemLayoutChanged)
{
*KPROCESS_GET_PTR(currentProcess, customFlags) = flags & ~MemLayoutChanged;
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onMemoryLayoutChangeEvent));
}
}
void postprocessSvc(void)
{
KThread *currentThread = currentCoreContext->objectContext.currentThread;
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread))
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread, rosalinaState & 5))
rosalinaRescheduleThread(currentThread, true);
officialPostProcessSvc();
@@ -91,10 +102,26 @@ void *svcHook(u8 *pageEnd)
u32 svcId = *(u8 *)(pageEnd - 0xB5);
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
switch(svcId)
{
case 0x01:
return ControlMemoryHookWrapper;
case 0x03: /* svcExitProcess */
{
// Signal that the process is about to be terminated
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
if (flags & SignalOnExit)
{
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onProcessExitEvent));
KEvent* event = (KEvent *)KProcessHandleTable__ToKAutoObject(handleTableOfProcess(currentProcess),
KPROCESS_GET_RVALUE(currentProcess, resumeProcessExitEvent));
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event);
}
return officialSVCs[0x3];
}
case 0x29:
return GetHandleInfoHookWrapper;
case 0x2A:
@@ -136,7 +163,7 @@ void *svcHook(u8 *pageEnd)
return invalidateEntireInstructionCache;
case 0xA0:
return MapProcessMemoryEx;
return MapProcessMemoryExWrapper;
case 0xA1:
return UnmapProcessMemoryEx;
case 0xA2:
@@ -148,6 +175,8 @@ void *svcHook(u8 *pageEnd)
return CopyHandleWrapper;
case 0xB2:
return TranslateHandleWrapper;
case 0xB3:
return ControlProcess;
default:
return (svcId <= 0x7D) ? officialSVCs[svcId] : NULL;

View File

@@ -0,0 +1,220 @@
#include "svc/ControlProcess.h"
#include "memory.h"
#include "mmu.h"
#include "synchronization.h"
typedef bool (*ThreadPredicate)(KThread *thread);
static void rosalinaLockThread(KThread *thread)
{
KThread *syncThread = synchronizationMutex->owner;
if(syncThread == NULL || syncThread != thread)
rosalinaRescheduleThread(thread, true);
}
Result ControlProcess(Handle processHandle, ProcessOp op, u32 varg2, u32 varg3)
{
Result res = 0;
KProcess *process;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
if(processHandle == CUR_PROCESS_HANDLE)
{
process = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)process);
}
else
process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
if(process == NULL)
return 0xD8E007F7; // invalid handle
switch (op)
{
case PROCESSOP_GET_ALL_HANDLES:
{
KProcessHandleTable *table = handleTableOfProcess(process);
u32 *originalHandleList = (u32 *)varg2;
u32 count = 0;
u32 searchForToken = varg3;
HandleDescriptor *handleDesc = table->handleTable == NULL ? table->internalTable : table->handleTable;
for (u32 idx = 0; idx < (u32)table->maxHandleCount; ++idx, ++handleDesc)
{
if (handleDesc->pointer == NULL)
continue;
if (searchForToken)
{
KClassToken token;
handleDesc->pointer->vtable->GetClassToken(&token, handleDesc->pointer);
if (searchForToken != token.flags)
continue;
}
*originalHandleList++ = idx | ((handleDesc->info << 16) >> 1);
++count;
}
res = count;
break;
}
case PROCESSOP_SET_MMU_TO_RWX:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
*KPROCESS_GET_PTR(process, customFlags) |= ForceRWXPages;
KProcessHwInfo__SetMMUTableToRWX(hwInfo);
break;
}
case PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT:
{
// Only accept current process for this command
if (process != currentCoreContext->objectContext.currentProcess)
{
res = 0xD8E007F7; // invalid handle
break;
}
Handle *onMemoryLayoutChangeEvent = KPROCESS_GET_PTR(process, onMemoryLayoutChangeEvent);
if (*onMemoryLayoutChangeEvent == 0)
res = CreateEvent(onMemoryLayoutChangeEvent, RESET_ONESHOT);
if (res >= 0)
{
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnMemLayoutChanges;
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onMemoryLayoutChangeEvent);
createHandleForThisProcess((Handle *)varg2, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< This avoid an extra operation on process exit
///< Closing the handle in the handle table will destroy the event
}
break;
}
case PROCESSOP_GET_ON_EXIT_EVENT:
{
// Only accept current process for this command
if (process != currentCoreContext->objectContext.currentProcess)
{
res = 0xD8E007F7; // invalid handle
break;
}
Handle *onProcessExitEvent = KPROCESS_GET_PTR(process, onProcessExitEvent);
Handle *resumeProcessExitEvent = KPROCESS_GET_PTR(process, resumeProcessExitEvent);
if (*onProcessExitEvent == 0)
res = CreateEvent(onProcessExitEvent, RESET_ONESHOT);
if (*resumeProcessExitEvent == 0)
res |= CreateEvent(resumeProcessExitEvent, RESET_ONESHOT);
if (res >= 0)
{
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnExit;
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onProcessExitEvent);
createHandleForThisProcess((Handle *)varg2, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
event = KProcessHandleTable__ToKAutoObject(handleTable, *resumeProcessExitEvent);
createHandleForThisProcess((Handle *)varg3, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
}
break;
}
case PROCESSOP_GET_PA_FROM_VA:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 pa = KProcessHwInfo__GetPAFromVA(hwInfo, varg3);
*(u32 *)varg2 = pa;
if (pa == 0)
res = 0xE0E01BF5; ///< Invalid address
break;
}
case PROCESSOP_SCHEDULE_THREADS:
{
ThreadPredicate threadPredicate = (ThreadPredicate)varg3;
KRecursiveLock__Lock(criticalSectionLock);
if (varg2 == 0) // Unlock
{
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);
}
}
else // Lock
{
bool currentThreadsFound = false;
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if(thread->ownerProcess != process
|| (threadPredicate != NULL && !threadPredicate(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(thread->ownerProcess != process
|| (threadPredicate != NULL && !threadPredicate(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);
break;
}
default:
res = 0xF8C007F4;
}
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
return res;
}

View File

@@ -29,11 +29,14 @@
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
{
if(type == 0x10000) // KDebug and KProcess: get context ID
Result res = 0;
if(type >= 0x10000)
{
KProcessHwInfo *hwInfo;
KProcessHwInfo *hwInfo;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KAutoObject *obj;
KAutoObject *obj;
if(handle == CUR_PROCESS_HANDLE)
{
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
@@ -45,18 +48,82 @@ Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
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;
switch (type)
{
case 0x10000: ///< Get ctx id (should probably move it to GetProcessInfo)
{
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;
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
break;
}
case 0x10001: ///< Get referenced object flags (token)
{
KClassToken token;
obj->vtable->GetClassToken(&token, obj);
*out = token.flags;
break;
}
case 0x10002: ///< Get object owner
{
Handle hOut;
KClassToken token;
KProcess * owner = NULL;
obj->vtable->GetClassToken(&token, obj);
switch(token.flags)
{
case TOKEN_KEVENT:
owner = ((KEvent *)obj)->owner;
break;
case TOKEN_KSEMAPHORE:
owner = ((KSemaphore *)obj)->owner;
break;
case TOKEN_KTIMER:
owner = ((KTimer *)obj)->owner;
break;
case TOKEN_KMUTEX:
owner = ((KMutex *)obj)->owner;
break;
case TOKEN_KDEBUG:
owner = ((KDebug *)obj)->owner;
break;
case TOKEN_KTHREAD:
owner = ((KThread *)obj)->ownerProcess;
break;
case TOKEN_KADDRESSARBITER:
owner = ((KAddressArbiter *)obj)->owner;
break;
case TOKEN_KSHAREDMEMORY:
owner = ((KSharedMemory *)obj)->owner;
break;
default:
break;
}
if (owner == NULL)
res = 0xD8E007F7;
res = createHandleForThisProcess(&hOut, (KAutoObject *)owner);
*out = hOut;
break;
}
default:
res = 0xF8C007F4;
break;
}
obj->vtable->DecrementReferenceCount(obj);
return 0;
return res;
}
else
return GetHandleInfo(out, handle, type);
return GetHandleInfo(out, handle, type);
}

View File

@@ -79,6 +79,14 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
*out = ttb & ~((1 << (14 - TTBCR)) - 1);
break;
}
case 0x10009:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 mmusize = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableSize);
u32 mmupa = (u32)PA_FROM_VA_PTR(KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA));
*out = (s64)(mmusize | ((s64)mmupa << 32));
break;
}
default:
res = 0xD8E007ED; // invalid enum value
break;

View File

@@ -64,6 +64,9 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
case 0x101:
*out = cfwInfo.rosalinaMenuCombo;
break;
case 0x102:
*out = cfwInfo.rosalinaFlags;
break;
case 0x200: // isRelease
*out = cfwInfo.flags & 1;
@@ -79,10 +82,15 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
break;
case 0x300: // K11Ext size
*out = (s64)(__end__ - __start__);
*out = (s64)(((u64)kextBasePa << 32) | (u64)(__end__ - __start__));
break;
case 0x301: // stolen SYSTEM memory size
*out = stolenSystemMemRegionSize;
break;
default:
*out = 0;
res = 0xF8C007F4; // not implemented
break;
}
@@ -105,13 +113,16 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
*out = L2C_CTRL & 1;
break;
default:
*out = 0;
res = 0xF8C007F4;
break;
}
}
else
{
*out = 0;
res = 0xF8C007F4;
}
break;
}
@@ -128,7 +139,10 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
if((u32)param <= getNumberOfCores())
*out = L1MMUTableAddrs[param - 1];
else
{
*out = 0;
res = 0xF8C007F4;
}
break;
}
@@ -136,6 +150,13 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
break;
}
case 0x20000:
{
*out = 0;
return 1;
}
default:
GetSystemInfo(out, type, param);
break;

View File

@@ -35,6 +35,7 @@
static u32 nbEnabled = 0;
static u32 maskedPids[MAX_DEBUG];
static u32 masks[MAX_DEBUG][8] = {0};
static u32 *homeBtnPressed = NULL;
bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId)
{
@@ -104,14 +105,22 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
__ldrex((s32 *)&rosalinaState);
}
while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1)));
__dmb();
if(rosalinaState & 2)
if(rosalinaState & 0x10)
hasStartedRosalinaNetworkFuncsOnce = true;
if(rosalinaState & 1)
rosalinaLockAllThreads();
else if(varg1 & 1)
rosalinaUnlockAllThreads();
// 1: all applet/app/dsp/csnd... threads 2: gsp 4: hid/ir
for (u32 v = 4; v != 0; v >>= 1)
{
if (varg1 & v)
{
if (rosalinaState & v)
rosalinaLockThreads(v);
else
rosalinaUnlockThreads(v);
}
}
break;
}
@@ -178,6 +187,15 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
KRecursiveLock__Unlock(&dbgParamsLock);
break;
}
case 0x10007:
{
// A bit crude but do the job for a simple notification + reboot, nothing sensitive here
if (varg1 > 255 && homeBtnPressed == NULL)
homeBtnPressed = PA_FROM_VA_PTR((u32 *)varg1);
else if (homeBtnPressed != NULL && *homeBtnPressed == 0)
*homeBtnPressed = varg1;
break;
}
default:
{
res = KernelSetState(type, varg1, varg2, varg3);

View File

@@ -26,19 +26,61 @@
#include "svc/MapProcessMemoryEx.h"
Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size)
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size)
{
Result res = 0;
u32 sizeInPage = size >> 12;
KLinkedList list;
KProcess *srcProcess;
KProcess *dstProcess;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
KProcess *process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
if(process == NULL)
if (dstProcessHandle == CUR_PROCESS_HANDLE)
{
dstProcess = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)dstProcess);
}
else
dstProcess = KProcessHandleTable__ToKProcess(handleTable, dstProcessHandle);
if (dstProcess == NULL)
return 0xD8E007F7;
Result res = KProcessHwInfo__MapProcessMemory(currentHwInfo, hwInfoOfProcess(process), dst, src, size >> 12);
if (srcProcessHandle == CUR_PROCESS_HANDLE)
{
srcProcess = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)srcProcess);
}
else
srcProcess = KProcessHandleTable__ToKProcess(handleTable, srcProcessHandle);
KAutoObject *obj = (KAutoObject *)process;
obj->vtable->DecrementReferenceCount(obj);
if (srcProcess == NULL)
{
res = 0xD8E007F7;
goto exit1;
}
KLinkedList__Initialize(&list);
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfoOfProcess(srcProcess), &list, vaSrc, sizeInPage);
if (res >= 0)
{
// Check if the destination address is free and large enough
res = KProcessHwInfo__CheckVaState(hwInfoOfProcess(dstProcess), vaDst, size, 0, 0);
if (res == 0)
res = KProcessHwInfo__MapListOfKBlockInfo(hwInfoOfProcess(dstProcess), vaDst, &list, 0x5806, MEMPERM_RW | 0x18, 0);
}
KLinkedList_KBlockInfo__Clear(&list);
((KAutoObject *)srcProcess)->vtable->DecrementReferenceCount((KAutoObject *)srcProcess);
exit1:
((KAutoObject *)dstProcess)->vtable->DecrementReferenceCount((KAutoObject *)dstProcess);
invalidateEntireInstructionCache();
flushEntireDataCache();
return res;
}

View File

@@ -28,9 +28,16 @@
#include "svc/SendSyncRequest.h"
#include "ipc.h"
static inline bool isNdmuWorkaround(const SessionInfo *info, u32 pid)
{
return info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce && pid >= nbSection0Modules;
}
Result SendSyncRequestHook(Handle handle)
{
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
KProcessHandleTable *handleTable = handleTableOfProcess(currentProcess);
u32 pid = idOfProcess(currentProcess);
KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, handle);
u32 *cmdbuf = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->threadLocalStorage + 0x80);
@@ -47,12 +54,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x10042:
{
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && kernelVersion >= SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
{
res = doPublishToProcessHook(handle, cmdbuf);
skip = true;
}
else if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce)
if(isNdmuWorkaround(info, pid))
{
cmdbuf[0] = 0x10040;
cmdbuf[1] = 0;
@@ -92,7 +94,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x20002:
{
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce)
if(isNdmuWorkaround(info, pid))
{
cmdbuf[0] = 0x20040;
cmdbuf[1] = 0;
@@ -105,7 +107,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x50100:
{
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && (strcmp(info->name, "srv:") == 0 || (kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)))
if(info != NULL && (strcmp(info->name, "srv:") == 0 || (GET_VERSION_MINOR(kernelVersion) < 39 && strcmp(info->name, "srv:pm") == 0)))
{
char name[9] = { 0 };
memcpy(name, cmdbuf + 1, 8);
@@ -134,7 +136,7 @@ Result SendSyncRequestHook(Handle handle)
if(!hasStartedRosalinaNetworkFuncsOnce)
break;
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
skip = info != NULL && strcmp(info->name, "ndm:u") == 0; // SuspendScheduler
skip = isNdmuWorkaround(info, pid); // SuspendScheduler
if(skip)
cmdbuf[1] = 0;
break;
@@ -145,7 +147,7 @@ Result SendSyncRequestHook(Handle handle)
if(!hasStartedRosalinaNetworkFuncsOnce)
break;
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "ndm:u") == 0) // ResumeScheduler
if(isNdmuWorkaround(info, pid)) // ResumeScheduler
{
cmdbuf[0] = 0x90040;
cmdbuf[1] = 0;
@@ -154,18 +156,6 @@ Result SendSyncRequestHook(Handle handle)
break;
}
case 0x4010042:
{
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
{
res = doPublishToProcessHook(handle, cmdbuf);
skip = true;
}
break;
}
case 0x4010082:
{
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);

View File

@@ -29,12 +29,45 @@
Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size)
{
if(kernelVersion < SYSTEM_VERSION(2, 37, 0)) // < 6.x
if (GET_VERSION_MINOR(kernelVersion) < 37) // < 6.x
return UnmapProcessMemory(processHandle, dst, size); // equivalent when size <= 64MB
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
Result res = 0;
u32 sizeInPage = size >> 12;
KLinkedList list;
KProcess *process;
KProcessHwInfo *hwInfo;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
Result res = KProcessHwInfo__UnmapProcessMemory(currentHwInfo, dst, size >> 12);
if (processHandle == CUR_PROCESS_HANDLE)
{
process = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)process);
}
else
process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
if (process == NULL)
return 0xD8E007F7;
hwInfo = hwInfoOfProcess(process);
KLinkedList__Initialize(&list);
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfo, &list, (u32)dst, sizeInPage);
if (res >= 0)
{
// Check for dst address to be in the right state (0x5806 as we set it with svcMapProcessMemoryEx)
res = KProcessHwInfo__CheckVaState(hwInfo, (u32)dst, size, 0x5806, 0);
if (res == 0)
res = KProcessHwInfo__MapListOfKBlockInfo(hwInfo, (u32)dst, &list, 0, 0, 0);
}
KLinkedList_KBlockInfo__Clear(&list);
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
invalidateEntireInstructionCache();
flushEntireDataCache();

View File

@@ -84,3 +84,12 @@ ControlMemoryEx:
ldr r1, [sp, #12]
add sp, #20
pop {pc}
.global MapProcessMemoryExWrapper
.type MapProcessMemoryExWrapper, %function
MapProcessMemoryExWrapper:
push {lr}
str r4, [sp, #-4]!
bl MapProcessMemoryEx
add sp, #4
pop {pc}

View File

@@ -66,17 +66,12 @@ void KThread__DebugReschedule(KThread *this, bool lock)
KRecursiveLock__Unlock(criticalSectionLock);
}
bool rosalinaThreadLockPredicate(KThread *thread)
static void rosalinaLockThread(KThread *thread)
{
KProcess *process = thread->ownerProcess;
if(process == NULL)
return false;
KThread *syncThread = synchronizationMutex->owner;
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))));
if(syncThread == NULL || syncThread != thread)
rosalinaRescheduleThread(thread, true);
}
void rosalinaRescheduleThread(KThread *thread, bool lock)
@@ -89,20 +84,45 @@ void rosalinaRescheduleThread(KThread *thread, bool lock)
else
thread->schedulingMask &= ~0x40;
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
if (oldSchedulingMask != thread->schedulingMask)
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
KRecursiveLock__Unlock(criticalSectionLock);
}
void rosalinaLockThread(KThread *thread)
bool rosalinaThreadLockPredicate(KThread *thread, u32 mask)
{
KThread *syncThread = synchronizationMutex->owner;
KProcess *process = thread->ownerProcess;
if(process == NULL || idOfProcess(process) < nbSection0Modules)
return false;
if(syncThread == NULL || syncThread != thread)
rosalinaRescheduleThread(thread, true);
u64 titleId = codeSetOfProcess(process)->titleId;
u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)(titleId & ~0xF0000001); // clear N3DS and SAFE_FIRM bits
if (mask & 1)
{
if (highTitleId != 0x00040130) // non-sysmodules
return true;
else
return lowTitleId == 0x1A02 || lowTitleId == 0x2702; // dsp, csnd
}
if (mask & 2)
{
if (highTitleId != 0x00040130) // non-sysmodules
false;
return lowTitleId == 0x1C02; // gsp
}
if (mask & 4)
{
if (highTitleId != 0x00040130) // non-sysmodules
return false;
return lowTitleId == 0x1D02 || lowTitleId == 0x3302;
}
return false;
}
void rosalinaLockAllThreads(void)
void rosalinaLockThreads(u32 mask)
{
bool currentThreadsFound = false;
@@ -110,7 +130,7 @@ void rosalinaLockAllThreads(void)
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if(!rosalinaThreadLockPredicate(thread))
if(!rosalinaThreadLockPredicate(thread, mask))
continue;
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
currentThreadsFound = true;
@@ -123,7 +143,7 @@ void rosalinaLockAllThreads(void)
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if(!rosalinaThreadLockPredicate(thread))
if(!rosalinaThreadLockPredicate(thread, mask))
continue;
if(!(thread->schedulingMask & 0x40))
{
@@ -145,7 +165,7 @@ void rosalinaLockAllThreads(void)
KRecursiveLock__Unlock(criticalSectionLock);
}
void rosalinaUnlockAllThreads(void)
void rosalinaUnlockThreads(u32 mask)
{
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
@@ -154,7 +174,7 @@ void rosalinaUnlockAllThreads(void)
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
continue;
if(thread->schedulingMask & 0x40)
if((thread->schedulingMask & 0x40) && rosalinaThreadLockPredicate(thread, mask))
rosalinaRescheduleThread(thread, false);
}
}

View File

@@ -96,6 +96,36 @@ KObjectMutex__Release:
blx r12
bx lr
.global KProcessHwInfo__MapL1Section_Hook
.type KProcessHwInfo__MapL1Section_Hook, %function
KProcessHwInfo__MapL1Section_Hook:
@r0 => hwInfo
@sp + 0x34 => our ptr to state
add r1, sp, #0x34
str lr, [sp, #-4]!
bl PatchDescriptorAccessControl
ldr lr, [sp], #4
ldmfd sp, {r0-r4}
sub sp, sp, #0x14
add r4, sp, #0x48
mov r11, #0
mov pc, lr
.global KProcessHwInfo__MapL2Section_Hook
.type KProcessHwInfo__MapL2Section_Hook, %function
KProcessHwInfo__MapL2Section_Hook:
@r0 => hwInfo
@sp + 0x34 => our ptr to state
add r1, sp, #0x34
str lr, [sp, #-4]!
bl PatchDescriptorAccessControl
ldr lr, [sp], #4
ldmfd sp, {r0-r4}
sub sp, sp, #0x4C
mov r4, r1
mov r6, r2
mov pc, lr
.global safecpy
.type safecpy, %function
safecpy:
@@ -121,12 +151,14 @@ _safecpy_end:
.section .rodata.safecpy_sz, "a", %progbits
.global safecpy_sz
.type safecpy_sz, %object
safecpy_sz: .word _safecpy_end - safecpy
.section .bss.SGI0Handler, "aw", %nobits
.balign 4
.global SGI0Handler
.type safecpy_sz, %object
SGI0Handler: .skip 4 @ see synchronization.c
.balign 4
@@ -136,4 +168,5 @@ SGI0Handler: .skip 4 @ see synchronization.c
_customInterruptEventObj: .word SGI0Handler
.global customInterruptEvent
.type safecpy_sz, %object
customInterruptEvent: .word _customInterruptEventObj

View File

@@ -37,7 +37,7 @@ CFLAGS := -std=gnu11 $(COMMON_FLAGS)
CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17 $(COMMON_FLAGS)
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),--section-start,.text=0x14000000
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
LIBS := -lctru

View File

@@ -2,8 +2,6 @@
#include <3ds/exheader.h>
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
Result hbldrInit(void);
void hbldrExit(void);

View File

@@ -4,9 +4,10 @@
#include "ifile.h"
#include "util.h"
#include "hbldr.h"
#include "luma_shared_config.h"
extern u32 config, multiConfig, bootConfig;
extern bool isN3DS, needToInitSd, isSdMode;
extern bool isN3DS, isSdMode;
static u8 g_ret_buf[sizeof(ExHeader_Info)];
static u64 g_cached_programHandle;
@@ -91,6 +92,11 @@ static int lzss_decompress(u8 *end)
return ret;
}
static inline bool hbldrIs3dsxTitle(u64 tid)
{
return Luma_SharedConfig->use_hbldr && tid == Luma_SharedConfig->hbldr_3dsx_tid;
}
static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags)
{
u32 dummy;
@@ -148,6 +154,21 @@ static Result loadCode(u64 titleId, prog_addrs_t *shared, u64 programHandle, int
return 0;
}
static Result PLGLDR_Init(Handle *session)
{
Result res;
while (1)
{
res = svcConnectToPort(session, "plg:ldr");
if (R_LEVEL(res) != RL_PERMANENT ||
R_SUMMARY(res) != RS_NOTFOUND ||
R_DESCRIPTION(res) != RD_NOT_FOUND
) break;
svcSleepThread(500000);
}
return res;
}
static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
{
Result res = 0;
@@ -169,23 +190,19 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
}
}
s64 nbSection0Modules;
svcGetSystemInfo(&nbSection0Modules, 26, 0);
// Force always having sdmc:/ and nand:/rw permission
exheaderInfo->aci.local_caps.storage_info.fs_access_info |= FSACCESS_NANDRW | FSACCESS_SDMC_RW;
// Tweak 3dsx placeholder title exheaderInfo
if (nbSection0Modules == 6 && exheaderInfo->aci.local_caps.title_id == HBLDR_3DSX_TID)
if (hbldrIs3dsxTitle(exheaderInfo->aci.local_caps.title_id))
{
assertSuccess(hbldrInit());
HBLDR_PatchExHeaderInfo(exheaderInfo);
hbldrExit();
}
u64 originaltitleId = exheaderInfo->aci.local_caps.title_id;
if(CONFIG(PATCHGAMES) && loadTitleExheaderInfo(exheaderInfo->aci.local_caps.title_id, exheaderInfo))
exheaderInfo->aci.local_caps.title_id = originaltitleId;
else
{
u64 originaltitleId = exheaderInfo->aci.local_caps.title_id;
if(CONFIG(PATCHGAMES) && loadTitleExheaderInfo(exheaderInfo->aci.local_caps.title_id, exheaderInfo))
exheaderInfo->aci.local_caps.title_id = originaltitleId;
}
return res;
}
@@ -205,7 +222,7 @@ static Result LoadProcess(Handle *process, u64 programHandle)
u64 titleId;
// make sure the cached info corrosponds to the current programHandle
if (g_cached_programHandle != programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID)
if (g_cached_programHandle != programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
{
res = GetProgramInfo(&g_exheaderInfo, programHandle);
g_cached_programHandle = programHandle;
@@ -231,7 +248,7 @@ static Result LoadProcess(Handle *process, u64 programHandle)
titleId = g_exheaderInfo.aci.local_caps.title_id;
ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info;
if (titleId == HBLDR_3DSX_TID)
if (hbldrIs3dsxTitle(titleId))
{
assertSuccess(hbldrInit());
assertSuccess(HBLDR_LoadProcess(&codeset, csi->text.address, flags & 0xF00, titleId, csi->name));
@@ -255,6 +272,9 @@ static Result LoadProcess(Handle *process, u64 programHandle)
// load code
if (R_SUCCEEDED(res = loadCode(titleId, &sharedAddr, programHandle, csi->flags.compress_exefs_code)))
{
u32 *code = (u32 *)sharedAddr.text_addr;
bool isHomebrew = code[0] == 0xEA000006 && code[8] == 0xE1A0400E;
memcpy(&codesetinfo.name, csi->name, 8);
codesetinfo.program_id = titleId;
codesetinfo.text_addr = vaddr.text_addr;
@@ -271,7 +291,37 @@ static Result LoadProcess(Handle *process, u64 programHandle)
{
res = svcCreateProcess(process, codeset, g_exheaderInfo.aci.kernel_caps.descriptors, count);
svcCloseHandle(codeset);
res = R_SUCCEEDED(res) ? 0 : res;
if (res >= 0)
{
// Try to load a plugin for the game
if (!isHomebrew && ((u32)((titleId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000))
{
// Special case handling: games rebooting the 3DS on old models
if (!isN3DS && g_exheaderInfo.aci.local_caps.core_info.o3ds_system_mode > 0)
{
// Check if the plugin loader is enabled, otherwise skip the loading part
s64 out;
svcGetSystemInfo(&out, 0x10000, 0x102);
if ((out & 1) == 0)
return 0;
}
Handle plgldr = 0;
if (R_SUCCEEDED(PLGLDR_Init(&plgldr)))
{
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(1, 0, 2);
cmdbuf[1] = IPC_Desc_SharedHandles(1);
cmdbuf[2] = *process;
svcSendSyncRequest(plgldr);
svcCloseHandle(plgldr);
}
}
return 0;
}
}
}
@@ -378,7 +428,7 @@ void loaderHandleCommands(void *ctx)
break;
case 4: // GetProgramInfo
memcpy(&programHandle, &cmdbuf[1], 8);
if (programHandle != g_cached_programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID)
if (programHandle != g_cached_programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
{
res = GetProgramInfo(&g_exheaderInfo, programHandle);
g_cached_programHandle = R_SUCCEEDED(res) ? programHandle : 0;

View File

@@ -0,0 +1,28 @@
/* This paricular file is licensed under the following terms: */
/*
* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
* for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
* and redistribute it freely, subject to the following restrictions:
*
* The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
*
* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
* This notice may not be removed or altered from any source distribution.
*/
#pragma once
#include <3ds/types.h>
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
} LumaSharedConfig;
/// Luma shared config.
#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800))

View File

@@ -7,7 +7,7 @@
#include "service_manager.h"
u32 config, multiConfig, bootConfig;
bool isN3DS, needToInitSd, isSdMode;
bool isN3DS, isSdMode;
// MAKE SURE fsreg has been init before calling this
static Result fsldrPatchPermissions(void)
@@ -29,27 +29,38 @@ static inline void loadCFWInfo(void)
{
s64 out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 3));
if(svcGetSystemInfo(&out, 0x20000, 0) != 1) panic(0xDEADCAFE);
svcGetSystemInfo(&out, 0x10000, 3);
config = (u32)out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 4));
svcGetSystemInfo(&out, 0x10000, 4);
multiConfig = (u32)out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 5));
svcGetSystemInfo(&out, 0x10000, 5);
bootConfig = (u32)out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x201));
svcGetSystemInfo(&out, 0x10000, 0x201);
isN3DS = (bool)out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x202));
needToInitSd = (bool)out;
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x203));
svcGetSystemInfo(&out, 0x10000, 0x203);
isSdMode = (bool)out;
IFile file;
if(needToInitSd) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
}
// this is called before main
void __appInit()
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
// this is called after main exits
void __wrap_exit(int rc)
{
(void)rc;
// Not supposed to terminate... kernel will clean up the handles if it does happen anyway
svcExitProcess();
}
void __sync_init();
void __libc_init_array(void);
// called before main
void initSystem(void)
{
__sync_init();
loadCFWInfo();
Result res;
@@ -71,42 +82,8 @@ void __appInit()
assertSuccess(FSUSER_SetPriority(0));
assertSuccess(pxiPmInit());
}
// this is called after main exits
void __appExit()
{
pxiPmExit();
//fsldrExit();
svcCloseHandle(*fsGetSessionHandle());
fsRegExit();
srvExit();
}
// stubs for non-needed pre-main functions
void __sync_init();
void __sync_fini();
void __system_initSyscalls();
void __ctru_exit()
{
void __libc_fini_array(void);
__libc_fini_array();
__appExit();
__sync_fini();
svcExitProcess();
}
void initSystem()
{
void __libc_init_array(void);
__sync_init();
__system_initSyscalls();
__appInit();
__libc_init_array();
//__libc_init_array();
}
static const ServiceManagerServiceEntry services[] = {

View File

@@ -740,7 +740,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
}
}
else if(progId == 0x0004013000001702LL) //CFG
else if((progId & ~0xF0000001ULL) == 0x0004013000001702LL) //CFG, SAFE_FIRM CFG
{
static const u8 pattern[] = {
0x06, 0x46, 0x10, 0x48
@@ -826,7 +826,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
)) goto error;
}
else if(progId == 0x0004013000001A02LL) //DSP
else if((progId & ~0xF0000001ULL) == 0x0004013000001A02LL) //DSP, SAFE_FIRM DSP
{
static const u8 pattern[] = {
0xE3, 0x10, 0x10, 0x80, 0xE2

View File

@@ -35,11 +35,12 @@ enum singleOptions
PATCHVERSTRING,
SHOWGBABOOT,
PATCHUNITINFO,
DISABLEARM11EXCHANDLERS
DISABLEARM11EXCHANDLERS,
ENABLESAFEFIRMROSALINA,
};
extern u32 config, multiConfig, bootConfig;
extern bool isN3DS, needToInitSd, isSdMode;
extern bool isN3DS, isSdMode;
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress);
Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags);

View File

@@ -37,7 +37,7 @@ CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit
LIBS := -lctru

View File

@@ -3,7 +3,7 @@ Open source replacement of the Arm11 PM system module.
This is licensed under the MIT license.
# Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`.
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`.
# Credits
@fincs

View File

@@ -117,7 +117,11 @@ AccessControlInfo:
ServiceAccessControl:
# Note: pm also uses srv:pm and Loader but doesn't list them here.
- fs:REG
# Custom:
- fs:USER
FileSystemAccess:
# Custom
- DirectSdmc
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.

View File

@@ -129,16 +129,21 @@ Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_Syste
return res;
}
Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid)
Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags)
{
ProcessList_Lock(&g_manager.processList);
Result res;
memset(outProgramInfo, 0, sizeof(FS_ProgramInfo));
if (g_manager.runningApplicationData != NULL) {
*outTitleId = g_manager.runningApplicationData->titleId;
*outPid = g_manager.runningApplicationData->pid;
ProcessData *app = g_manager.runningApplicationData;
outProgramInfo->programId = app->titleId;
outProgramInfo->mediaType = app->mediaType;
*outPid = app->pid;
*outLaunchFlags = app->launchFlags;
res = 0;
} else {
*outTitleId = 0;
*outPid = 0;
res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
}
ProcessList_Unlock(&g_manager.processList);

View File

@@ -12,4 +12,4 @@ Result listMergeUniqueDependencies(ProcessData **procs, u64 *dependencies, u32 *
Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_SystemInfoFlags *outSiFlags, const FS_ProgramInfo *programInfo);
// Custom
Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid);
Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags);

View File

@@ -56,10 +56,12 @@ static Result loadWithoutDependencies(Handle *outDebug, ProcessData **outProcess
process->pid = pid;
process->titleId = exheaderInfo->aci.local_caps.title_id;;
process->programHandle = programHandle;
process->launchFlags = launchFlags; // not in official PM
process->flags = 0; // will be filled later
process->terminatedNotificationVariation = (launchFlags & 0xF0) >> 4;
process->terminationStatus = TERMSTATUS_RUNNING;
process->refcount = 1;
process->mediaType = programInfo->mediaType; // not in official PM
ProcessList_Unlock(&g_manager.processList);
svcSignalEvent(g_manager.newProcessEvent);
@@ -71,7 +73,11 @@ static Result loadWithoutDependencies(Handle *outDebug, ProcessData **outProcess
u32 serviceCount;
for(serviceCount = 0; serviceCount < 34 && *(u64 *)localcaps->service_access[serviceCount] != 0; serviceCount++);
TRY(FSREG_Register(pid, programHandle, programInfo, &localcaps->storage_info));
// Not in official PM: patch local caps to give access to everything
ExHeader_Arm11StorageInfo storageInfo = localcaps->storage_info;
storageInfo.fs_access_info = 0xFFFFFFFF;
TRY(FSREG_Register(pid, programHandle, programInfo, &storageInfo));
TRY(SRVPM_RegisterProcess(pid, serviceCount, localcaps->service_access));
if (localcaps->reslimit_category <= RESLIMIT_CATEGORY_OTHER) {
@@ -135,6 +141,11 @@ static Result loadWithDependencies(Handle *outDebug, ProcessData **outProcessDat
process->flags |= PROCESSFLAG_DEPENDENCIES_LOADED;
}
if (launchFlags & PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING) {
// See no evil
numUnique = 0;
}
/*
Official pm does this:
for each dependency:
@@ -207,8 +218,9 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
programInfoUpdate = (launchFlags & PMLAUNCHFLAG_USE_UPDATE_TITLE) ? programInfoUpdate : programInfo;
TRY(registerProgram(&programHandle, programInfo, programInfoUpdate));
u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
res = LOADER_GetProgramInfo(exheaderInfo, programHandle);
res = R_SUCCEEDED(res) && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res;
res = R_SUCCEEDED(res) && coreVer == 2 && exheaderInfo->aci.local_caps.core_info.core_version != coreVer ? (Result)0xC8A05800 : res;
if (R_FAILED(res)) {
LOADER_UnregisterProgram(programHandle);
@@ -216,21 +228,21 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
}
// Change APPMEMALLOC if needed
if (IS_N3DS && APPMEMTYPE == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
if (IS_N3DS && OS_KernelConfig->app_memtype == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
u32 limitMb;
SystemMode n3dsSystemMode = exheaderInfo->aci.local_caps.core_info.n3ds_system_mode;
if ((launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) || n3dsSystemMode == SYSMODE_O3DS_PROD) {
if ((launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) & PMLAUNCHFLAG_FORCE_USE_O3DS_MAX_APP_MEM) {
limitMb = 96;
} else {
switch (exheaderInfo->aci.local_caps.core_info.o3ds_system_mode) {
case SYSMODE_O3DS_PROD: limitMb = 64; break;
case SYSMODE_DEV1: limitMb = 96; break;
case SYSMODE_DEV2: limitMb = 80; break;
default: limitMb = 0; break;
}
bool forceO3dsAppMem = (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) != 0;
if (forceO3dsAppMem && (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_MAX_APP_MEM) != 0) {
setAppMemLimit(96 << 20);
} else if (forceO3dsAppMem || n3dsSystemMode == SYSMODE_O3DS_PROD) {
switch (exheaderInfo->aci.local_caps.core_info.o3ds_system_mode) {
case SYSMODE_O3DS_PROD: limitMb = 64; break;
case SYSMODE_DEV1: limitMb = 96; break;
case SYSMODE_DEV2: limitMb = 80; break;
default: limitMb = 0; break;
}
// Can be 0:
setAppMemLimit(limitMb << 20);
}
}
@@ -321,9 +333,11 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla
u32 tidh = (u32)(programInfo->programId >> 32);
u32 tidl = (u32)programInfo->programId;
if ((tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != SYSCOREVER) {
u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
if (coreVer == 2 && (tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != coreVer) {
// Panic if launching SAFE_MODE sysmodules or applets (note: exheader syscorever check above only done for applications in official PM)
// Official PM also hardcodes SYSCOREVER = 2 here.
// NATIVE_FIRM-only.
panic(4);
}
@@ -509,8 +523,8 @@ Result autolaunchSysmodules(void)
FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND };
// Launch NS
if (NSTID != 0) {
programInfo.programId = NSTID;
if (OS_KernelConfig->ns_tid != 0) {
programInfo.programId = OS_KernelConfig->ns_tid;
TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES));
}

View File

@@ -4,6 +4,11 @@
#include <3ds/services/fs.h>
#include "process_data.h"
/// Custom launch flags for PM launch commands.
enum {
PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24),
};
Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFlags);
Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags);
Result LaunchApp(const FS_ProgramInfo *programInfo, u32 launchFlags);

View File

@@ -3,11 +3,24 @@
#include "luma.h"
#include "util.h"
bool hasKExt(void)
{
s64 val;
return svcGetSystemInfo(&val, 0x20000, 0) == 1;
}
u32 getKExtSize(void)
{
s64 val;
Result res = svcGetSystemInfo(&val, 0x10000, 0x300);
return R_FAILED(res) ? 0 : (u32)val;
svcGetSystemInfo(&val, 0x10000, 0x300);
return (u32)val;
}
u32 getStolenSystemMemRegionSize(void)
{
s64 val;
svcGetSystemInfo(&val, 0x10000, 0x301);
return (u32)val;
}
bool isTitleLaunchPrevented(u64 titleId)
@@ -15,5 +28,5 @@ bool isTitleLaunchPrevented(u64 titleId)
s64 numKips = 0;
svcGetSystemInfo(&numKips, 26, 0);
return numKips >= 6 && (titleId & ~N3DS_TID_BIT) == 0x0004003000008A02ULL; // ErrDisp
}
return numKips >= 6 && (titleId & ~(N3DS_TID_MASK | 1)) == 0x0004003000008A02ULL; // ErrDisp
}

View File

@@ -2,5 +2,7 @@
#include <3ds/types.h>
bool hasKExt(void);
u32 getKExtSize(void);
bool isTitleLaunchPrevented(u64 titleId);
u32 getStolenSystemMemRegionSize(void);
bool isTitleLaunchPrevented(u64 titleId);

View File

@@ -14,10 +14,27 @@
#include "service_manager.h"
static MyThread processMonitorThread, taskRunnerThread;
static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0};
static u8 ALIGN(8) exheaderInfoBuffer[6 * sizeof(ExHeader_Info)] = {0};
static u8 ALIGN(8) threadStacks[2][THREAD_STACK_SIZE] = {0};
// this is called before main
void __appInit()
// this is called after main exits
void __wrap_exit(int rc)
{
(void)rc;
// Not supposed to terminate... kernel will clean up the handles if it does happen anyway
svcExitProcess();
}
Result __sync_init(void);
//void __libc_init_array(void);
// Called before main
void initSystem()
{
__sync_init();
//__libc_init_array();
// Wait for sm
for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) {
res = srvPmInit();
@@ -28,14 +45,27 @@ void __appInit()
loaderInit();
fsRegInit();
static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0};
static u8 ALIGN(8) exheaderInfoBuffer[6 * sizeof(ExHeader_Info)] = {0};
static u8 ALIGN(8) threadStacks[2][THREAD_STACK_SIZE] = {0};
// Init objects
Manager_Init(processDataBuffer, 0x40);
ExHeaderInfoHeap_Init(exheaderInfoBuffer, 6);
TaskRunner_Init();
}
static const ServiceManagerServiceEntry services[] = {
{ "pm:app", 4, pmAppHandleCommands, false },
{ "pm:dbg", 2, pmDbgHandleCommands, false },
{ NULL },
};
static const ServiceManagerNotificationEntry notifications[] = {
{ 0x000, NULL },
};
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
int main(void)
{
Result res = 0;
// Init the reslimits, register the KIPs and map the firmlaunch parameters
initializeReslimits();
@@ -48,51 +78,7 @@ void __appInit()
// Launch NS, etc.
autolaunchSysmodules();
}
// this is called after main exits
void __appExit()
{
// We don't clean up g_manager's handles because it could hang the process monitor thread, etc.
fsRegExit();
loaderExit();
srvPmExit();
}
Result __sync_init(void);
Result __sync_fini(void);
void __libc_init_array(void);
void __libc_fini_array(void);
void __ctru_exit()
{
__libc_fini_array();
__appExit();
__sync_fini();
svcExitProcess();
}
void initSystem()
{
__sync_init();
__appInit();
__libc_init_array();
}
static const ServiceManagerServiceEntry services[] = {
{ "pm:app", 3, pmAppHandleCommands, false },
{ "pm:dbg", 2, pmDbgHandleCommands, false },
{ NULL },
};
static const ServiceManagerNotificationEntry notifications[] = {
{ 0x000, NULL },
};
int main(void)
{
Result res = 0;
if (R_FAILED(res = ServiceManager_Run(services, notifications, NULL))) {
panic(res);
}

View File

@@ -7,6 +7,21 @@
Manager g_manager;
static void giveAllFsArchiveAccessToKip(u32 pid, u64 tid)
{
static const ExHeader_Arm11StorageInfo storageInfo = {
.fs_access_info = 0xFFFFFFFF,
};
static const u64 programHandle = 0xFFFF000000000000LL;
FS_ProgramInfo info = {
.programId = tid,
.mediaType = MEDIATYPE_NAND,
};
assertSuccess(FSREG_Register(pid, programHandle, &info, &storageInfo));
}
void Manager_Init(void *procBuf, size_t numProc)
{
memset(&g_manager, 0, sizeof(Manager));
@@ -34,14 +49,23 @@ void Manager_RegisterKips(void)
process->handle = processHandle;
process->pid = i;
process->refcount = 1;
process->titleId = 0x0004000100001000ULL; // note: same TID for all builtins
process->titleId = 0x0004000100001000ULL; // note: same internal TID for all builtins
process->flags = PROCESSFLAG_KIP;
process->terminationStatus = TERMSTATUS_RUNNING;
assertSuccess(svcSetProcessResourceLimits(processHandle, g_manager.reslimits[RESLIMIT_CATEGORY_OTHER]));
if (i < 5) {
// Exempt rosalina from being resource-limited at all
assertSuccess(svcSetProcessResourceLimits(processHandle, g_manager.reslimits[RESLIMIT_CATEGORY_OTHER]));
}
}
ProcessList_Unlock(&g_manager.processList);
// Give full archive access to us (PM) and Rosalina (real PIDs don't matter, they just have to be unique (?))
// Loader doesn't depend on PM and has its own fs:REG handle so it must do it itself.
giveAllFsArchiveAccessToKip(2, 0x0004013000001202LL); // PM
if (numKips > 5) {
giveAllFsArchiveAccessToKip(5, 0x0004013000006902LL); // Rosalina
}
}
Result UnregisterProcess(u64 titleId)
@@ -66,3 +90,27 @@ Result UnregisterProcess(u64 titleId)
ProcessList_Unlock(&g_manager.processList);
return 0;
}
Result PrepareToChainloadHomebrew(u64 titleId)
{
// Note: I'm allowing this command to be called for non-applications, maybe that'll be useful
// in the future...
ProcessData *foundProcess = NULL;
Result res;
ProcessList_Lock(&g_manager.processList);
foundProcess = ProcessList_FindProcessByTitleId(&g_manager.processList, titleId & ~N3DS_TID_MASK);
if (foundProcess != NULL) {
// Clear the "notify on termination, don't cleanup" flag, so that for ex. APT isn't notified & no need for UnregisterProcess,
// and the "dependencies loaded" flag, so that the dependencies aren't killed (for ex. when
// booting hbmenu instead of Home Menu, in which case the same title is going to be launched...)
foundProcess->flags &= ~(PROCESSFLAG_DEPENDENCIES_LOADED | PROCESSFLAG_NOTIFY_TERMINATION);
res = 0;
} else {
res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
}
ProcessList_Unlock(&g_manager.processList);
return res;
}

View File

@@ -21,3 +21,4 @@ extern Manager g_manager;
void Manager_Init(void *procBuf, size_t numProc);
void Manager_RegisterKips(void);
Result UnregisterProcess(u64 titleId);
Result PrepareToChainloadHomebrew(u64 titleId);

View File

@@ -3,6 +3,7 @@
#include "launch.h"
#include "info.h"
#include "util.h"
#include "manager.h"
void pmDbgHandleCommands(void *ctx)
{
@@ -11,10 +12,10 @@ void pmDbgHandleCommands(void *ctx)
u32 cmdhdr = cmdbuf[0];
FS_ProgramInfo programInfo;
Handle debug;
u64 titleId;
Handle debug;
u32 pid;
u32 launchFlags;
switch (cmdhdr >> 16) {
case 1:
@@ -40,12 +41,11 @@ void pmDbgHandleCommands(void *ctx)
// Custom
case 0x100:
titleId = 0;
pid = 0xFFFFFFFF;
cmdbuf[1] = GetCurrentAppTitleIdAndPid(&titleId, &pid);
cmdbuf[0] = IPC_MakeHeader(0x100, 4, 0);
memcpy(cmdbuf + 2, &titleId, 8);
cmdbuf[4] = pid;
cmdbuf[1] = GetCurrentAppInfo(&programInfo, &pid, &launchFlags);
cmdbuf[0] = IPC_MakeHeader(0x100, 7, 0);
memcpy(cmdbuf + 2, &programInfo, sizeof(FS_ProgramInfo));
cmdbuf[6] = pid;
cmdbuf[7] = launchFlags;
break;
case 0x101:
cmdbuf[1] = DebugNextApplicationByForce(cmdbuf[1] != 0);
@@ -59,7 +59,11 @@ void pmDbgHandleCommands(void *ctx)
cmdbuf[2] = IPC_Desc_MoveHandles(1);
cmdbuf[3] = debug;
break;
case 0x103:
memcpy(&titleId, cmdbuf + 1, 8);
cmdbuf[1] = PrepareToChainloadHomebrew(titleId);
cmdbuf[0] = IPC_MakeHeader(0x103, 1, 0);
break;
default:
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
cmdbuf[1] = 0xD900182F;

View File

@@ -29,10 +29,12 @@ typedef struct ProcessData {
u32 pid;
u64 titleId;
u64 programHandle;
u32 launchFlags;
u8 flags;
u8 terminatedNotificationVariation;
TerminationStatus terminationStatus;
u8 refcount;
FS_MediaType mediaType;
} ProcessData;
typedef struct ProcessList {

View File

@@ -29,7 +29,7 @@ static void cleanupProcess(ProcessData *process)
ProcessList_Lock(&g_manager.processList);
if (g_manager.runningApplicationData != NULL && process->handle == g_manager.runningApplicationData->handle) {
if (IS_N3DS && APPMEMTYPE == 6) {
if (IS_N3DS && OS_KernelConfig->app_memtype == 6) {
assertSuccess(resetAppMemLimit());
}
g_manager.runningApplicationData = NULL;

View File

@@ -4,6 +4,9 @@
#include "manager.h"
#include "luma.h"
#define CPUTIME_MULTI_MASK BIT(7)
#define CPUTIME_SINGLE_MASK 0
typedef s64 ReslimitValues[10];
static const ResourceLimitType g_reslimitInitOrder[10] = {
@@ -189,20 +192,23 @@ static ReslimitValues g_n3dsReslimitValues[4] = {
Both modes pause threads they don't want to run in thread selection, and unpause them when needed.
If the threads that are intended to be paused is running an SVC, the pause will happen *after* SVC return.
Mode0 (unsure)
Mode0 "multi"
Starting by "sysmodule" threads, alternatively allow (if preemptible) only sysmodule threads,
and then only application threads to run.
The latter has an exception; if "sysmodule" threads have run for less than 2usec, they
The latter has an exception; if "sysmodule" threads have run for less than 8usec (value is a kernel bug), they
are unpaused an allowed to run instead.
This happens at a rate of 1ms * (cpuTime/100).
This happens at a rate of 2ms * (cpuTime/100).
Mode1
Mode1 "single"
This mode is half-broken due to a kernel bug (when "current thread" is the priority 0 kernel thread).
When this mode is enabled, only one application thread is allowed to be created on core1.
This divides the core1 time into slices of 12.5ms.
This divides the core1 time into slices of 25ms.
The "application" thread is given cpuTime% of the slice.
The "sysmodules" threads are given a total of (90 - cpuTime)% of the slice.
@@ -243,7 +249,11 @@ static ReslimitValues *fixupReslimitValues(void)
{
// In order: APPLICATION, SYS_APPLET, LIB_APPLET, OTHER
// Fixup "commit" reslimit
u32 sysmemalloc = SYSMEMALLOC + getKExtSize();
// Note: we lie in the reslimit and make as if neither KExt nor Roslina existed, to avoid breakage
u32 appmemalloc = OS_KernelConfig->memregion_sz[0];
u32 sysmemalloc = OS_KernelConfig->memregion_sz[1] + (hasKExt() ? getStolenSystemMemRegionSize() : 0);
ReslimitValues *values = !IS_N3DS ? g_o3dsReslimitValues : g_n3dsReslimitValues;
static const u32 minAppletMemAmount = 0x1200000;
@@ -252,7 +262,7 @@ static ReslimitValues *fixupReslimitValues(void)
u32 baseRegionSize = !IS_N3DS ? 0x1400000 : 0x2000000;
if (sysmemalloc < minAppletMemAmount) {
values[1][0] = SYSMEMALLOC - minAppletMemAmount / 3;
values[1][0] = sysmemalloc - minAppletMemAmount / 3;
values[2][0] = 0;
values[3][0] = baseRegionSize + otherMinOvercommitAmount;
} else {
@@ -262,8 +272,8 @@ static ReslimitValues *fixupReslimitValues(void)
values[3][0] = baseRegionSize + (otherMinOvercommitAmount + excess / 4);
}
values[0][0] = APPMEMALLOC;
g_defaultAppMemLimit = APPMEMALLOC;
values[0][0] = appmemalloc;
g_defaultAppMemLimit = appmemalloc;
return values;
}
@@ -315,22 +325,23 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
- app has a non-0 cputime descriptor in exhdr: maximum core1 cputime reslimit and scheduling
mode are set according to it. Current reslimit is set to 0. SetAppResourceLimit *is* needed
to use core1.
- app has a 0 cputime descriptor: maximum is set to 80.
Current reslimit is set to 0, and SetAppResourceLimit *is* needed
- app has a 0 cputime descriptor: maximum is set to 80, scheduling mode to "single" (broken).
Current reslimit is set to 0, and SetAppResourceLimit *is* also needed
to use core1, **EXCEPT** for an hardcoded set of titles.
*/
u8 cpuTime = (u8)descriptor;
assertSuccess(setAppCpuTimeLimit(0)); // remove preemption first.
g_manager.cpuTimeBase = 0;
u32 currentValueToSet = g_manager.cpuTimeBase; // 0
if (cpuTime != 0) {
// Set core1 scheduling mode
g_manager.maxAppCpuTime = cpuTime & 0x7F;
assertSuccess(svcKernelSetState(6, 3, (cpuTime & 0x80) ? 0LL : 1LL));
} else {
if (cpuTime == 0) {
// 2.0 apps have this exheader field correctly filled, very often to 0x9E (1.0 titles don't).
u32 titleUid = ((u32)titleId >> 8) & 0xFFFFF;
g_manager.maxAppCpuTime = 80;
// Default setting is 80% max "single", with a current value of 0
cpuTime = CPUTIME_SINGLE_MASK | 80;
static const u32 numOverrides = sizeof(g_startCpuTimeOverrides) / sizeof(g_startCpuTimeOverrides[0]);
if (titleUid >= g_startCpuTimeOverrides[0].titleUid && titleUid <= g_startCpuTimeOverrides[numOverrides - 1].titleUid) {
@@ -338,15 +349,26 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
for (u32 i = 0; i < numOverrides && titleUid < g_startCpuTimeOverrides[i].titleUid; i++);
if (i < numOverrides) {
if (g_startCpuTimeOverrides[i].value > 100 && g_startCpuTimeOverrides[i].value < 200) {
assertSuccess(svcKernelSetState(6, 3, 0LL));
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value - 100));
cpuTime = CPUTIME_MULTI_MASK | 80; // "multi", max 80%
currentValueToSet = g_startCpuTimeOverrides[i].value - 100;
} else {
assertSuccess(svcKernelSetState(6, 3, 1LL));
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value));
cpuTime = CPUTIME_SINGLE_MASK | 80; // "single", max 80%
currentValueToSet = g_startCpuTimeOverrides[i].value;
}
}
}
}
// Set core1 scheduling mode
assertSuccess(svcKernelSetState(6, 3, (cpuTime & CPUTIME_MULTI_MASK) ? 0LL : 1LL));
// Set max value (limit)
g_manager.maxAppCpuTime = cpuTime & 0x7F;
// Set current value (for 1.0 apps)
if (currentValueToSet != 0) {
assertSuccess(setAppCpuTimeLimit(currentValueToSet));
}
}
Result SetAppResourceLimit(u32 mbz, ResourceLimitType category, u32 value, u64 mbz2)

View File

@@ -4,6 +4,11 @@
TaskRunner g_taskRunner;
static void taskRunnerNoOpFunction(void *args)
{
(void)args;
}
void TaskRunner_Init(void)
{
memset(&g_taskRunner, 0, sizeof(TaskRunner));
@@ -20,12 +25,23 @@ void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsi
LightEvent_Signal(&g_taskRunner.parametersSetEvent);
}
void TaskRunner_Terminate(void)
{
g_taskRunner.shouldTerminate = true;
TaskRunner_RunTask(taskRunnerNoOpFunction, NULL, 0);
}
void TaskRunner_HandleTasks(void *p)
{
(void)p;
for (;;) {
while (!g_taskRunner.shouldTerminate) {
LightEvent_Signal(&g_taskRunner.readyEvent);
LightEvent_Wait(&g_taskRunner.parametersSetEvent);
g_taskRunner.task(g_taskRunner.argStorage);
}
}
void TaskRunner_WaitReady(void)
{
LightEvent_Wait(&g_taskRunner.readyEvent);
}

View File

@@ -8,11 +8,15 @@ typedef struct TaskRunner {
LightEvent parametersSetEvent;
void (*task)(void *argdata);
u8 argStorage[0x40];
bool shouldTerminate;
} TaskRunner;
extern TaskRunner g_taskRunner;
void TaskRunner_Init(void);
void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsize);
void TaskRunner_Terminate(void);
/// Thread function
void TaskRunner_HandleTasks(void *p);
void TaskRunner_WaitReady(void);

View File

@@ -6,6 +6,15 @@
#include "exheader_info_heap.h"
#include "task_runner.h"
void forceMountSdCard(void)
{
FS_Archive sdmcArchive;
assertSuccess(fsInit());
assertSuccess(FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")));
// No need to clean up things as we will firmlaunch straight away
}
static Result terminateUnusedDependencies(const u64 *dependencies, u32 numDeps)
{
ProcessData *process;
@@ -65,6 +74,16 @@ static Result terminateProcessImpl(ProcessData *process, ExHeader_Info *exheader
}
}
static void terminateProcessByIdChecked(u32 pid)
{
ProcessData *process = ProcessList_FindProcessById(&g_manager.processList, pid);
if (process != NULL) {
ProcessData_SendTerminationNotification(process);
} else {
panic(0LL);
}
}
static Result commitPendingTerminations(s64 timeout)
{
// Wait for all of the processes that have received notification 0x100 to terminate
@@ -247,6 +266,8 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
u64 dependencies[48];
u32 numDeps = 0;
s64 numKips = 0;
svcGetSystemInfo(&numKips, 26, 0);
ExHeader_Info *exheaderInfo = ExHeaderInfoHeap_New();
@@ -269,6 +290,12 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
}
ProcessList_Lock(&g_manager.processList);
// Send custom notification to at least Rosalina to make it relinquish some non-KIP services handles, stop the debugger, etc.
if (numKips >= 6) {
notifySubscribers(0x2000);
}
// Send notification 0x100 to the currently running application
if (g_manager.runningApplicationData != NULL) {
g_manager.runningApplicationData->flags &= ~PROCESSFLAG_DEPENDENCIES_LOADED;
@@ -302,20 +329,29 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
commitPendingTerminations(timeoutTicks >= 0 ? ticksToNs(timeoutTicks) : 0LL);
g_manager.waitingForTermination = false;
// Now, send termination notification to PXI (PID 4)
if (callerPid == (u32)-1) {
// On firmlaunch, try to force Process9 to mount the SD card to allow the Process9 firmlaunch patch to load boot.firm if needed
// Need to do that before we tell PXI to terminate
s64 out;
if(R_SUCCEEDED(svcGetSystemInfo(&out, 0x10000, 0x203)) && out != 0) {
// If boot.firm is on the SD card, then...
forceMountSdCard();
}
}
// Now, send termination notification to PXI (PID 4). Also do the same for Rosalina.
assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent));
g_manager.waitingForTermination = true;
ProcessList_Lock(&g_manager.processList);
process = ProcessList_FindProcessById(&g_manager.processList, 4);
if (process != NULL) {
ProcessData_SendTerminationNotification(process);
} else {
panic(0LL);
if (numKips >= 6) {
terminateProcessByIdChecked(5); // Rosalina
}
terminateProcessByIdChecked(4); // PXI
ProcessList_Unlock(&g_manager.processList);
// Allow 1.5 extra seconds for PXI (approx 402167783 ticks)
// Allow 1.5 extra seconds for PXI and Rosalina (approx 402167783 ticks)
timeoutTicks = dstTimePoint - svcGetSystemTick();
commitPendingTerminations(1500 * 1000 * 1000LL + (timeoutTicks >= 0 ? ticksToNs(timeoutTicks) : 0LL));
g_manager.waitingForTermination = false;

View File

@@ -8,13 +8,7 @@
#define REG32(reg) (*(vu32 *)reg)
#define REG64(reg) (*(vu64 *)reg)
#define NSTID REG64(0x1FF80008)
#define SYSCOREVER REG32(0x1FF80010)
#define APPMEMTYPE REG32(0x1FF80030)
#define APPMEMALLOC REG32(0x1FF80040)
#define SYSMEMALLOC REG32(0x1FF80044)
#define IS_N3DS (*(vu32 *)0x1FF80030 >= 6) // APPMEMTYPE. Hacky but doesn't use APT
#define IS_N3DS (OS_KernelConfig->app_memtype >= 6) // APPMEMTYPE. Hacky but doesn't use APT
#define N3DS_TID_MASK 0xF0000000ULL
#define N3DS_TID_BIT 0x20000000ULL

View File

@@ -37,7 +37,7 @@ CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit
LIBS := -lctru

View File

@@ -3,7 +3,7 @@ Open source replacement of the Arm11 PXI system module.
This is licensed under the MIT license.
# Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
# Credits
This list is not complete at all:

View File

@@ -7,7 +7,6 @@ This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE fo
*/
#include <string.h>
#include "PXI.h"
#include "common.h"
#include "MyThread.h"
@@ -99,10 +98,40 @@ static inline void exitPXI(void)
static u8 ALIGN(8) receiverStack[THREAD_STACK_SIZE];
static u8 ALIGN(8) senderStack[THREAD_STACK_SIZE];
static u8 ALIGN(8) PXISRV11HandlerStack[THREAD_STACK_SIZE];
static MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
Result __sync_init(void);
Result __sync_fini(void);
void __libc_fini_array(void);
void __libc_init_array(void);
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
// this is called after main exits
void __wrap_exit(int rc)
{
(void)rc;
srvExit();
exitPXI();
svcCloseHandle(terminationRequestedEvent);
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
svcCloseHandle(sessionManager.replySemaphore);
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
//__libc_fini_array();
__sync_fini();
svcExitProcess();
}
// this is called before main
void __appInit()
void initSystem(void)
{
__sync_init();
assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY));
assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT));
@@ -117,52 +146,13 @@ void __appInit()
if(R_FAILED(res) && res != (Result)0xD88007FA)
svcBreak(USERBREAK_PANIC);
}
}
// this is called after main exits
void __appExit()
{
srvExit();
exitPXI();
svcCloseHandle(terminationRequestedEvent);
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
svcCloseHandle(sessionManager.replySemaphore);
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
}
// stubs for non-needed pre-main functions
void __system_initSyscalls(){}
Result __sync_init(void);
Result __sync_fini(void);
void __ctru_exit()
{
void __libc_fini_array(void);
__libc_fini_array();
__appExit();
__sync_fini();
svcExitProcess();
}
void initSystem()
{
void __libc_init_array(void);
__sync_init();
__system_initSyscalls();
__appInit();
__libc_init_array();
//__libc_init_array();
}
int main(void)
{
Handle handles[10] = {0}; //notification handle + service handles
MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
for(u32 i = 0; i < 9; i++)
assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1));

View File

@@ -28,8 +28,9 @@ INCLUDES := include include/gdb include/menus include/redshift
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
DEFINES := -DARM11 -D_3DS
CFLAGS := -g -std=gnu11 -Wall -Wextra -Werror -Wno-unused-value -Os -mword-relocations \
-fomit-frame-pointer -ffunction-sections -fdata-sections -fno-math-errno \
CFLAGS := -g -std=gnu11 -Wall -Wextra -Wno-unused-value -O2 -mword-relocations \
-fomit-frame-pointer -ffunction-sections -fdata-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE)
@@ -37,9 +38,9 @@ CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),--section-start,.text=0x14000000
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
LIBS := -lctru
LIBS := -lm -lctru
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
@@ -130,6 +131,8 @@ $(OUTPUT).elf : $(OFILES)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
@$(NM) -CSn $@ > $(notdir $*.lst)
draw.o: CFLAGS += -O3
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------

View File

@@ -0,0 +1,37 @@
#pragma once
#include <3ds/types.h>
#include "ifile.h"
#define _3GX_MAGIC (0x3130303024584733) /* "3GX$0001" */
typedef struct PACKED
{
u32 authorLen;
const char * authorMsg;
u32 titleLen;
const char * titleMsg;
u32 summaryLen;
const char * summaryMsg;
u32 descriptionLen;
const char * descriptionMsg;
} _3gx_Infos;
typedef struct PACKED
{
u32 count;
u32 * titles;
} _3gx_Targets;
typedef struct PACKED
{
u64 magic;
u32 version;
u32 codeSize;
u32 * code;
_3gx_Infos infos;
_3gx_Targets targets;
} _3gx_Header;
Result Read_3gx_Header(IFile *file, _3gx_Header *header);
Result Read_3gx_Code(IFile *file, _3gx_Header *header, void *dst);

View File

@@ -71,18 +71,20 @@ void svcInvalidateEntireInstructionCache(void);
///@{
/**
* @brief Maps a block of process memory.
* @param process Handle of the process.
* @param dstProcessHandle Handle of the process to map the memory in (destination)
* @param destAddress Address of the mapped block in the current process.
* @param srcProcessHandle Handle of the process to map the memory from (source)
* @param srcAddress Address of the mapped block in the source process.
* @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes).
*/
Result svcMapProcessMemoryEx(Handle process, u32 destAddr, u32 srcAddr, u32 size);
Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 vaSrc, u32 size);
/**
* @brief Unmaps a block of process memory.
* @param process Handle of the process.
* @param destAddress Address of the block of memory to unmap, in the current (destination) process.
* @param process Handle of the process to unmap the memory from
* @param destAddress Address of the block of memory to unmap
* @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes).
* This function should only be used to unmap memory mapped with svcMapProcessMemoryEx
*/
Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size);
@@ -134,4 +136,19 @@ Result svcCopyHandle(Handle *out, Handle outProcess, Handle in, Handle inProcess
* @param in The input handle.
*/
Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in);
/// Operations for svcControlProcess
typedef enum ProcessOp
{
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
PROCESSOP_GET_ON_EXIT_EVENT,
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
} ProcessOp;
Result svcControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);
///@}

View File

@@ -54,9 +54,14 @@
#define GPU_TRANSFER_CNT REG32(0x10400C18)
#define GPU_CMDLIST_CNT REG32(0x104018F0)
#define LCD_TOP_BRIGHTNESS REG32(0x10202240)
#define LCD_BOT_BRIGHTNESS REG32(0x10202A40)
#define FB_BOTTOM_VRAM_ADDR ((void *)0x1F48F000) // cached
#define FB_BOTTOM_VRAM_PA 0x1848F000
#define FB_BOTTOM_SIZE (320 * 240 * 2)
#define FB_SCREENSHOT_SIZE (52 + 400 * 240 * 3)
#define SCREEN_BOT_WIDTH 320
#define SCREEN_BOT_HEIGHT 240
@@ -68,23 +73,35 @@
#define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F)
#define COLOR_RED RGB565(0x1F, 0x00, 0x00)
#define COLOR_GREEN RGB565(0x00, 0x1F, 0x00)
#define COLOR_LIME RGB565(0x00, 0xFF, 0x00)
#define COLOR_BLACK RGB565(0x00, 0x00, 0x00)
#define DRAW_MAX_FORMATTED_STRING_SIZE 512
void Draw_Init(void);
void Draw_Lock(void);
void Draw_Unlock(void);
void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character);
u32 Draw_DrawString(u32 posX, u32 posY, u32 color, const char *string);
__attribute__((format(printf,4,5)))
u32 Draw_DrawFormattedString(u32 posX, u32 posY, u32 color, const char *fmt, ...);
void Draw_FillFramebuffer(u32 value);
void Draw_ClearFramebuffer(void);
void Draw_SetupFramebuffer(void);
Result Draw_AllocateFramebufferCache(u32 size);
Result Draw_AllocateFramebufferCacheForScreenshot(u32 size);
void Draw_FreeFramebufferCache(void);
void *Draw_GetFramebufferCache(void);
u32 Draw_GetFramebufferCacheSize(void);
u32 Draw_SetupFramebuffer(void);
void Draw_RestoreFramebuffer(void);
void Draw_FlushFramebuffer(void);
u32 Draw_GetCurrentFramebufferAddress(bool top, bool left);
// Width is actually height as the 3ds screen is rotated 90 degrees
void Draw_GetCurrentScreenInfo(u32 *width, bool *is3d, bool top);
void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth);
void Draw_ConvertFrameBufferLine(u8 *line, bool top, bool left, u32 y);
void Draw_ConvertFrameBufferLines(u8 *buf, u32 width, u32 startingLine, u32 numLines, bool top, bool left);

View File

@@ -12,11 +12,14 @@
#define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name)
#define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name)
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ConvertVAToPA);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ListAllHandles);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(CatchSvc);
GDB_DECLARE_QUERY_HANDLER(Rcmd);

View File

@@ -31,6 +31,6 @@
#include "MyThread.h"
#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
void HBLDR_RestartHbApplication(void *p);
void HBLDR_HandleCommands(void *ctx);

View File

@@ -36,4 +36,5 @@ extern int inputRedirectionStartResult;
MyThread *inputRedirectionCreateThread(void);
void inputRedirectionThreadMain(void);
Result InputRedirection_Disable(s64 timeout);
Result InputRedirection_DoOrUndoPatches(void);

View File

@@ -0,0 +1,28 @@
/* This paricular file is licensed under the following terms: */
/*
* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
* for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
* and redistribute it freely, subject to the following restrictions:
*
* The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
*
* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
* This notice may not be removed or altered from any source distribution.
*/
#pragma once
#include <3ds/types.h>
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
} LumaSharedConfig;
/// Luma shared config.
#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800))

View File

@@ -0,0 +1,33 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2020 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.
*/
#pragma once
#include <3ds/types.h>
u32 getMinLuminancePreset(void);
u32 getMaxLuminancePreset(void);
u32 getCurrentLuminance(bool top);

View File

@@ -30,6 +30,8 @@
#include <string.h>
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
void *memset32(void *dest, u32 value, u32 size);
void hexItoa(u64 number, char *out, u32 digits, bool uppercase);
unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);
unsigned long long int xstrtoull(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);

View File

@@ -27,33 +27,25 @@
#pragma once
#include <3ds/types.h>
#include <3ds/services/hid.h>
#include "MyThread.h"
#include "utils.h"
#define HID_PAD (REG32(0x10146000) ^ 0xFFF)
#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7)
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define DEFAULT_MENU_COMBO (BUTTON_L1 | BUTTON_DOWN | BUTTON_SELECT)
#define DEFAULT_MENU_COMBO (KEY_L | KEY_DDOWN | KEY_SELECT)
#define DIRECTIONAL_KEYS (KEY_DOWN | KEY_UP | KEY_LEFT | KEY_RIGHT)
#define CORE_APPLICATION 0
#define CORE_SYSTEM 1
typedef enum MenuItemAction {
METHOD,
MENU
MENU_END = 0,
METHOD = 1,
MENU = 2,
} MenuItemAction;
typedef struct MenuItem {
const char *title;
@@ -62,27 +54,37 @@ typedef struct MenuItem {
struct Menu *menu;
void (*method)(void);
};
bool (*visibility)(void);
} MenuItem;
typedef struct Menu {
const char *title;
u32 nbItems;
MenuItem items[0x40];
MenuItem items[16];
} Menu;
extern bool terminationRequest;
extern Handle terminationRequestEvent;
extern bool isN3DS;
extern bool menuShouldExit;
extern bool preTerminationRequested;
extern Handle preTerminationEvent;
extern u32 menuCombo;
u32 waitInputWithTimeout(u32 msec);
u32 waitInputWithTimeout(s32 msec);
u32 waitInput(void);
u32 waitComboWithTimeout(u32 msec);
u32 waitComboWithTimeout(s32 msec);
u32 waitCombo(void);
bool menuCheckN3ds(void);
u32 menuCountItems(const Menu *menu);
MyThread *menuCreateThread(void);
void menuEnter(void);
void menuLeave(void);
void menuThreadMain(void);
void menuShow(Menu *root);
void menuEnter(void);
void menuLeave(void);
void menuThreadMain(void);
void menuShow(Menu *root);
void DispMessage(const char *title, const char *message);
u32 DispErrMessage(const char *title, const char *message, const Result error);
void DisplayPluginMenu(u32 *cmdbuf);

View File

@@ -33,8 +33,12 @@
extern Menu rosalinaMenu;
void RosalinaMenu_TakeScreenshot(void);
void RosalinaMenu_ChangeScreenBrightness(void);
void RosalinaMenu_ShowCredits(void);
void RosalinaMenu_ProcessList(void);
void RosalinaMenu_PowerOff(void);
void RosalinaMenu_Reboot(void);
void RosalinaMenu_Cheats(void);
bool rosalinaMenuShouldShowDebugInfo(void);
void RosalinaMenu_ShowDebugInfo(void);

View File

@@ -33,4 +33,5 @@
#define CHEATS_PER_MENU_PAGE 18
void RosalinaMenu_Cheats(void);
void Cheat_ApplyCheats();
void Cheat_SeedRng(u64 seed);
void Cheat_ApplyCheats(void);

View File

@@ -32,6 +32,8 @@
extern Menu debuggerMenu;
void debuggerFetchAndSetNextApplicationDebugHandleTask(void *argdata);
Result debuggerDisable(s64 timeout);
void DebuggerMenu_EnableDebugger(void);
void DebuggerMenu_DisableDebugger(void);
void DebuggerMenu_DebugNextApplicationByForce(void);

View File

@@ -30,12 +30,18 @@
extern Menu screenFiltersMenu;
int screenFiltersCurrentTemperature;
extern int screenFiltersCurrentTemperature;
void screenFiltersSetDisabled(void);
void screenFiltersReduceBlueLevel1(void);
void screenFiltersReduceBlueLevel2(void);
void screenFiltersReduceBlueLevel3(void);
void screenFiltersReduceBlueLevel4(void);
void screenFiltersReduceBlueLevel5(void);
void screenFiltersSetTemperature(int temperature);
void ScreenFiltersMenu_RestoreCct(void);
void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
void ScreenFiltersMenu_SetAquarium(void); // 10000K
void ScreenFiltersMenu_SetOvercastSky(void); // 7500K
void ScreenFiltersMenu_SetDaylight(void); // 5500K
void ScreenFiltersMenu_SetFluorescent(void); // 4200K
void ScreenFiltersMenu_SetHalogen(void); // 3400K
void ScreenFiltersMenu_SetIncandescent(void); // 2700K
void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K
void ScreenFiltersMenu_SetCandle(void); // 1900K
void ScreenFiltersMenu_SetEmber(void); // 1200K

View File

@@ -30,8 +30,12 @@
#include "menu.h"
extern Menu sysconfigMenu;
extern bool isConnectionForced;
void SysConfigMenu_UpdateStatus(bool control);
void SysConfigMenu_ToggleLEDs(void);
void SysConfigMenu_ToggleWireless(void);
void SysConfigMenu_TogglePowerButton(void);
void SysConfigMenu_ControlWifi(void);
void SysConfigMenu_DisableForcedWifiConnection(void);

View File

@@ -18,13 +18,14 @@
#include <errno.h>
#define SYNC_ERROR ENODEV
extern Handle SOCU_handle;
extern Handle socMemhandle;
extern bool miniSocEnabled;
Result miniSocInit();
Result miniSocInit(void);
void miniSocLockState(void);
void miniSocUnlockState(bool force);
Result miniSocExitDirect(void);
Result miniSocExit(void);
s32 _net_convert_error(s32 sock_retval);
@@ -37,10 +38,17 @@ int socConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int socPoll(struct pollfd *fds, nfds_t nfds, int timeout);
int socSetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int socClose(int sockfd);
long socGethostid(void);
ssize_t soc_recv(int sockfd, void *buf, size_t len, int flags);
ssize_t soc_send(int sockfd, const void *buf, size_t len, int flags);
ssize_t socRecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t socSendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
// actually provided by ctrulib
ssize_t soc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t soc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
static inline ssize_t socRecv(int sockfd, void *buf, size_t len, int flags)
{
return socRecvfrom(sockfd, buf, len, flags, NULL, 0);
}
static inline ssize_t socSend(int sockfd, const void *buf, size_t len, int flags)
{
return socSendto(sockfd, buf, len, flags, NULL, 0);
}

View File

@@ -30,4 +30,4 @@
#include <time.h>
Result ntpGetTimeStamp(time_t *outTimestamp);
Result ntpSetTimeDate(const struct tm *localt);
Result ntpSetTimeDate(time_t timestamp);

View File

@@ -0,0 +1,32 @@
#pragma once
#include <3ds/types.h>
#define MAX_BUFFER (50)
#define MAX_ITEMS_COUNT (64)
typedef struct
{
bool noFlash;
u32 lowTitleId;
char path[256];
u32 config[32];
} PluginLoadParameters;
typedef struct
{
u32 nbItems;
u8 states[MAX_ITEMS_COUNT];
char title[MAX_BUFFER];
char items[MAX_ITEMS_COUNT][MAX_BUFFER];
char hints[MAX_ITEMS_COUNT][MAX_BUFFER];
} PluginMenu;
Result plgLdrInit(void);
void plgLdrExit(void);
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled);
Result PLGLDR__SetPluginLoaderState(bool enabled);
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters);
Result PLGLDR__DisplayMenu(PluginMenu *menu);
Result PLGLDR__DisplayMessage(const char *title, const char *body);
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error);

View File

@@ -0,0 +1,9 @@
#pragma once
#include <3ds/types.h>
#include "MyThread.h"
MyThread * PluginLoader__CreateThread(void);
bool PluginLoader__IsEnabled(void);
void PluginLoader__MenuCallback(void);
void PluginLoader__UpdateMenu(void);

View File

@@ -6,6 +6,12 @@
#include <3ds/services/pmapp.h>
#include <3ds/services/pmdbg.h>
Result PMDBG_GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid);
/// Custom launch flags for PM launch commands.
enum {
PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24),
};
Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags);
Result PMDBG_DebugNextApplicationByForce(bool debug);
Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags);
Result PMDBG_PrepareToChainloadHomebrew(u64 titleId);

View File

@@ -29,4 +29,5 @@
#include <3ds/types.h>
#include "menu.h"
void ProcessPatchesMenu_PatchUnpatchFSDirectly(void);
Result OpenProcessByName(const char *name, Handle *h);
Result PatchProcessByName(const char *name, Result (*func)(u32 size));

View File

@@ -0,0 +1,31 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2018 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.
*/
#pragma once
void Sleep__Init(void);
void Sleep__HandleNotification(u32 notifId);
bool Sleep__Status(void);

View File

@@ -68,11 +68,13 @@ typedef struct sock_server
sock_free_func free;
Handle shall_terminate_event;
Result init_result;
} sock_server;
Result server_init(struct sock_server *serv);
void server_bind(struct sock_server *serv, u16 port);
Result server_bind(struct sock_server *serv, u16 port);
void server_run(struct sock_server *serv);
void server_kill_connections(struct sock_server *serv);
void server_set_should_close_all(struct sock_server *serv);
void server_finalize(struct sock_server *serv);
bool Wifi__IsConnected(void);

View File

@@ -9,6 +9,7 @@ typedef struct TaskRunner {
LightEvent parametersSetEvent;
void (*task)(void *argdata);
u8 argStorage[0x40];
bool shouldTerminate;
} TaskRunner;
extern TaskRunner g_taskRunner;
@@ -17,6 +18,8 @@ MyThread *taskRunnerCreateThread(void);
void TaskRunner_Init(void);
void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsize);
void TaskRunner_Terminate(void);
/// Thread function
void TaskRunner_HandleTasks(void);
void TaskRunner_WaitReady(void);
void TaskRunner_WaitReady(void);

View File

@@ -27,8 +27,11 @@
#pragma once
#include <3ds/svc.h>
#include <3ds/srv.h>
#include <3ds/result.h>
#include <3ds/ipc.h>
#include "csvc.h"
#include "luma_shared_config.h"
// For accessing physmem uncached (and directly)
#define PA_PTR(addr) (void *)((u32)(addr) | 1 << 31)
@@ -56,4 +59,28 @@ static inline void *decodeArmBranch(const void *src)
return (void *)((const u8 *)src + 8 + off);
}
static inline void assertSuccess(Result res)
{
if(R_FAILED(res))
svcBreak(USERBREAK_PANIC);
}
static inline void error(u32* cmdbuf, Result rc)
{
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
cmdbuf[1] = rc;
}
extern bool isN3DS;
Result OpenProcessByName(const char *name, Handle *h);
Result SaveSettings(void);
static inline bool isServiceUsable(const char *name)
{
bool r;
return R_SUCCEEDED(srvIsServiceRegistered(&r, name)) && r;
}
void formatMemoryPermission(char *outbuf, MemPerm perm);
void formatUserMemoryState(char *outbuf, MemState state);
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle);

View File

@@ -21,7 +21,7 @@ AccessControlInfo:
IdealProcessor : 1
AffinityMask : 3
Priority : 20
Priority : 25 # 55
DisableDebug : false
EnableForceDebug : true
@@ -37,7 +37,7 @@ AccessControlInfo:
CoreVersion : 2
DescVersion : 2
MemoryType : System # Application / System / Base
MemoryType : Base # Application / System / Base
HandleTableSize: 150
MemoryMapping:

View File

@@ -0,0 +1,62 @@
#include <3ds.h>
#include "3gx.h"
Result Read_3gx_Header(IFile *file, _3gx_Header *header)
{
u64 total;
char * dst;
Result res = 0;
res = IFile_Read(file, &total, header, sizeof(_3gx_Header));
if (R_FAILED(res))
return res;
// Read author
file->pos = (u32)header->infos.authorMsg;
dst = (char *)header + sizeof(_3gx_Header);
res = IFile_Read(file, &total, dst, header->infos.authorLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.authorMsg = dst;
// Read title
file->pos = (u32)header->infos.titleMsg;
dst += header->infos.authorLen;
res = IFile_Read(file, &total, dst, header->infos.titleLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.titleMsg = dst;
// Declare other members as null (unused in our case)
header->infos.summaryLen = 0;
header->infos.summaryMsg = NULL;
header->infos.descriptionLen = 0;
header->infos.descriptionMsg = NULL;
// Read targets compatibility
file->pos = (u32)header->targets.titles;
dst += header->infos.titleLen;
dst += 4 - ((u32)dst & 3); // 4 bytes aligned
res = IFile_Read(file, &total, dst, header->targets.count * sizeof(u32));
if (R_FAILED(res))
return res;
// Relocate ptr
header->targets.titles = (u32 *)dst;
return res;
}
Result Read_3gx_Code(IFile *file, _3gx_Header *header, void *dst)
{
u64 total;
Result res = 0;
file->pos = (u32)header->code;
res = IFile_Read(file, &total, dst, header->codeSize);
return res;
}

View File

@@ -59,7 +59,10 @@ SVC_BEGIN svcInvalidateEntireInstructionCache
SVC_END
SVC_BEGIN svcMapProcessMemoryEx
str r4, [sp, #-4]!
ldr r4, [sp, #4]
svc 0xA0
ldr r4, [sp], #4
bx lr
SVC_END
@@ -99,3 +102,8 @@ SVC_BEGIN svcTranslateHandle
str r1, [r2]
bx lr
SVC_END
SVC_BEGIN svcControlProcess
svc 0xB3
bx lr
SVC_END

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