Compare commits

...

290 Commits
v3.6 ... v6.1.1

Author SHA1 Message Date
Aurora
c711ed6253 Added a different error for < 3.x NANDs as they can not be booted currently 2016-08-27 00:34:25 +02:00
Aurora
356268eae5 Welcome back to the 1,25s speed boost 2016-08-26 22:24:23 +02:00
Aurora
2dd64b8a92 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-08-26 21:38:36 +02:00
Aurora
b5cddedb7d Fix config derp 2016-08-26 21:38:03 +02:00
TuxSH
7afdc2b3b5 "Fix" the twlbg patches and make them optional 2016-08-26 19:09:14 +02:00
Aurora
60c4956290 Fix wrong bootconfig being picked up by 3ds_injector, cleanup 2016-08-26 18:44:39 +02:00
TuxSH
7331a919e4 Fix bug. 2016-08-25 18:53:37 +02:00
TuxSH
33238cee54 Remove loading of /luma/TwlBg.cxi, fix bugs. 2016-08-25 16:39:43 +02:00
TuxSH
384dd2ad81 Implement on-the-fly patching of TwlBg
(and port the patches from https://github.com/ahezard/twl_firm_patcher; big thanks to ahezard and people mentioned in this page; also to Subv for the original patching idea (for NATIVE_FIRM))
2016-08-25 00:13:43 +02:00
TuxSH
74ac76ba84 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-08-21 22:09:47 +02:00
TuxSH
253e031f83 Add support for loading /luma/TwlBg.cxi (on dev branch this will take precedence) 2016-08-21 22:09:27 +02:00
TuxSH
ef1ecf859c Update draw.c 2016-08-20 19:59:25 +02:00
TuxSH
a302ad3bea R.I.P boot speed boost (for now) 2016-08-20 18:45:56 +02:00
TuxSH
b87dadbb72 Update patches.c 2016-08-18 00:36:28 +02:00
TuxSH
50a2424001 Implement svcGetCFWInfo in place of svc 0x2e (which is stubbed). Luma3DS now boots ca. 1.5s faster
Fix bug in pin.c where the START button wasn't recognized as well.
2016-08-17 23:47:30 +02:00
Aurora
4f8c66b2b7 There would not be an use for this 2016-08-16 22:59:25 +02:00
Aurora
4d9cbc4e19 Fix fail 2016-08-16 22:46:41 +02:00
Aurora
40369d44df Pin cleanup 2016-08-16 22:39:02 +02:00
Aurora
ee3720f0b7 Make loader more readable, use an array instead of a fixed location for the emuNAND test sector 2016-08-16 18:47:27 +02:00
Aurora
e5dcca1c2b Update gitignore 2016-08-16 01:59:23 +02:00
TuxSH
a381c2a811 Update config.c 2016-08-15 21:37:25 +02:00
TuxSH
eef30ceb3c Make the multi-choice options look cleaner 2016-08-15 21:25:06 +02:00
TuxSH
a1024c288e Update pin.c 2016-08-15 17:15:16 +02:00
TuxSH
d445b20e90 Fix bugs 2016-08-15 16:50:58 +02:00
Aurora
bb117d3d74 Clear screens before turning on the backlight to mitigate previous FB contents persisting 2016-08-15 15:25:44 +02:00
Aurora
c101653077 Clear screens before a power off/reboot 2016-08-15 14:46:33 +02:00
Aurora
5248b96f8a No need for this 2016-08-15 13:41:52 +02:00
Aurora
7ab59e420a Fix comment 2016-08-15 13:28:43 +02:00
Aurora
83a849126a Move stuff from firm.c (2) 2016-08-15 13:23:27 +02:00
Aurora
c9c373f607 Move stuff from firm.c 2016-08-15 13:11:27 +02:00
Aurora
aa7c2c0009 Various changes/cleanups, removed useless code, simplified chronometer functions 2016-08-15 03:51:48 +02:00
TuxSH
75acdc8a98 Fix setRSAMod0DerivedKeys 2016-08-14 23:32:56 +02:00
TuxSH
9b304404f7 Enable access to the ITCM (older k9lh payloads disabled access to it).
Thanks @Normmatt for reporting that bug.
2016-08-14 12:30:12 +02:00
TuxSH
95ef379ac5 Remove the empty "luma" folder from the output folder since it will be created automatically when running Luma3DS. 2016-08-13 23:56:07 +02:00
TuxSH
3bc966f84e Replace "Enable splash screen with no screen-init" by "Display splash screen before payloads".
The screens will be initied if and only if there are splash files to display.
2016-08-13 22:23:14 +02:00
TuxSH
457b4cec13 Disable interrupts and do some refactoring. 2016-08-13 20:49:40 +02:00
TuxSH
905777466d Don't set retail keys on dev units. 2016-08-06 22:38:06 +02:00
TuxSH
18b5cdcddf Don't make any assumption regarding version when loading an external firmware file. 2016-08-04 00:05:01 +02:00
TuxSH
389a169443 pin.c cleanup 2016-08-03 20:49:10 +02:00
TuxSH
e01802e299 Check the PIN before loading a payload.
Also fix some bugs.
2016-08-03 16:58:03 +02:00
TuxSH
709aefba5d Implement a PIN-checking system.
Idea and original code by @reworks
2016-08-03 14:13:26 +02:00
Aurora
e4ed713fce Update FatFs to 0.12a 2016-07-20 15:07:13 +02:00
Aurora
d3c507b0d4 Minor stuff 2016-07-20 00:11:59 +02:00
Aurora
a68e14def3 Added error screen when booting an unsupported NAND with no firmware.bin or writing to the config fails, added code for creating the "luma" directory if it is missing 2016-07-18 23:07:28 +02:00
Aurora
8175642a2a Fix changing the brightness
Needs to be static for some reason
2016-07-18 21:57:31 +02:00
Aurora
8d1befea9e Rename "Updated SysNAND" to reflect its only new purpose 2016-07-18 19:10:41 +02:00
Aurora
e7b8a0ef39 Force A9LH detection is not needed anymore 2016-07-18 18:53:23 +02:00
Aurora
be6ee894f9 Fix firmware.bin loading 2016-07-18 17:28:04 +02:00
Aurora
e0e8ed2113 Hardcode 9.6 FIRM version for firmware.bin 2016-07-18 17:13:46 +02:00
Aurora
c63e46b1a9 Added FIRM version detection, removed firmware.bin loading unless an unsupported O3DS NATIVE_FIRM (pre-5.0) is being loaded, skip patching old unsupported O3DS AGB/TWL FIRMs, only apply 11.0 patches with 11.0 or greater 2016-07-18 16:58:29 +02:00
Aurora
eb9c74a1ed Bool-ify 2016-07-18 15:46:29 +02:00
Aurora
efd83e063e Remove code to skip the rbeoot patch on 9.0 as it is not needed anymore with A9LH and constitutes a brick risk 2016-07-18 15:40:31 +02:00
Aurora
ae23a1c84d Fixed Luma allowing users to go to the configuration after AGB_FIRM quits 2016-07-18 15:09:04 +02:00
TuxSH
a0e8bc1de3 Add support for launching >= 6.x/7.x emuNANDs properly when the sysNAND is on a lower firmware version
To launch 3.x - 4.x emuNANDs, you'll need to use an external firmware file (10.x or so should do the trick)
2016-07-14 21:20:45 +02:00
TuxSH
72caad86cc Minor stuff 2016-07-05 16:05:53 +02:00
TuxSH
575adcbb9d Revert part of 136e0d89 (due to cache issues) 2016-07-03 20:53:13 +02:00
TuxSH
53d2aac2ae Update CakeBrah 2016-07-02 17:38:33 +02:00
TuxSH
96211813e3 Use bool instead of u32 where it's relevant 2016-07-02 14:44:01 +02:00
TuxSH
730e716f0f Update CakeBrah 2016-07-02 12:32:39 +02:00
TuxSH
2238293c0f Fix indentation 2016-07-02 10:59:21 +02:00
Aurora
29d8e637d8 One-liners ftw 2016-07-01 20:36:43 +02:00
Aurora
136e0d8974 Cleanup 2016-07-01 20:27:28 +02:00
TuxSH
61684ecb68 We need to clean and flush caches before jumping to payloads, actually. 2016-06-14 19:50:38 +02:00
TuxSH
159c9cb475 Implement our own DCache cleaning functions 2016-06-13 21:14:53 +02:00
TuxSH
2943dcb2e9 Refactor firm.c as well as other files 2016-06-12 22:14:52 +02:00
TuxSH
edfd63e1f7 We don't need to flush DCache when launching payloads.
Fixes a derp as well.
2016-06-10 23:33:03 +02:00
TuxSH
e593584a47 Move screen management code to screen.c and fix cache-related issues
- Screen brightness is now updated as soon as the user selects a brightness option, on all boot environments
- Payloads can now be 1KB bigger
- Some cache-related bugs may have been fixed
2016-06-10 21:48:22 +02:00
TuxSH
f78dd5365c External .code section loading for titles and some refactoring 2016-06-05 20:43:49 +02:00
TuxSH
ae1033d975 Update start.s (thanks @delebile and/or @d0k3) 2016-05-28 23:47:30 +02:00
Aurora
d239d82379 Fixed release archive building 2016-05-27 16:29:39 +02:00
Aurora
5fac49447c Update authors for the Cakehax loader 2016-05-27 14:08:06 +02:00
Aurora
30b3a51309 Cleanup 2016-05-27 04:16:49 +02:00
TuxSH
7ea2a0a278 Remove the anti-DG check on 11.0 firmware (and future ones) 2016-05-25 20:50:45 +02:00
TuxSH
a3ae38520c Fix the latest two commits 2016-05-25 20:08:37 +02:00
Aurora
c36fa01651 Move patches within emunand.c 2016-05-25 15:35:50 +02:00
Aurora
9aeac7af92 Move patches to patches.c and emunand.c, section 0 copying to launchFirm for consistency 2016-05-25 14:34:43 +02:00
TuxSH
859944dc8e Update Makefile 2016-05-21 22:59:14 +02:00
TuxSH
a6dc3c8fc7 Merge pull request #86 from mariogamer2/master
Print commit in settings
2016-05-21 10:50:11 +02:00
mariogamer2
61c02ed079 Print git commit in menu settings,taked from: 81566b7b27 2016-05-19 18:57:21 -04:00
TuxSH
afc6f51ff2 Revised and working RO patch 2016-05-14 20:26:32 +02:00
TuxSH
c32eefaa51 Patched CRO0/CRR0 hash&signature checks
This needs testing.
2016-05-14 15:35:59 +02:00
Aurora
050f433046 Small chrono function refactoring 2016-05-13 05:01:32 +02:00
Aurora
ffee64c67f Skip the svcBackdoor function on 9.0 O3DS FIRM - <= 9.5 N3DS FIRM 2016-05-12 15:28:48 +02:00
Aurora
8cbc535755 Minor pedantic changes (3) 2016-05-12 15:16:46 +02:00
TuxSH
76acfd9934 Minor pedantic changes (2) 2016-05-12 13:35:39 +02:00
TuxSH
06cc4f7172 Minor pedantic changes 2016-05-12 12:24:14 +02:00
Aurora
158659e5b0 More cleanup 2016-05-12 03:13:17 +02:00
Aurora
7e46046e3b Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-05-11 19:29:49 +02:00
Aurora
808c4b7361 Cleanup, possibly slight speedup by limiting Process9 memsearches to the P9 code 2016-05-11 19:28:45 +02:00
TuxSH
03dc4fc425 Update the FRIENDS module patch 2016-05-11 14:43:24 +02:00
TuxSH
1750b256eb Do things right 2016-05-11 01:08:54 +02:00
TuxSH
d00d82ac89 Update firm.c 2016-05-10 23:27:54 +02:00
TuxSH
edb5a82a89 Restore svcBackdoor (on ARM11, for 11.0 and higher) 2016-05-10 23:06:32 +02:00
TuxSH
f7552f7c32 Update patcher.c 2016-05-10 02:12:44 +02:00
TuxSH
4483b65b25 Update config.c 2016-05-10 01:38:08 +02:00
TuxSH
d2f53626ae Add precise and reliable time measurement (with a resolution of 67MHz).
Splash screens now last 3 seconds after they have been loaded.
The delay after pressing START in the configuration menu is now 2s long.
2016-05-10 01:27:58 +02:00
Aurora
2fd8c7aace Moved GPU register clearing to the config only, as it causes artifacts 2016-05-09 14:38:20 +02:00
Aurora
b90b138766 Cleanup, fix latest ctrulib, removed reboot after config (needs testing!), fixed L+SELECT payload 2016-05-09 03:41:29 +02:00
TuxSH
c3ad7eda08 Derp 2016-05-08 17:59:15 +02:00
TuxSH
be54052b6d Make 3ds_injector able to be bigger than the official loader module (max. 25KB on O3DS due to memory limitations). Thanks @mid-kid for the idea. 2016-05-07 23:40:02 +02:00
TuxSH
9e87679ee2 Use a much better algorithm for getLoader (Luma3DS boots around 0.25s faster now) 2016-05-07 19:16:53 +02:00
TuxSH
4b500349e6 Update README.md 2016-05-06 18:34:35 +02:00
TuxSH
8e554e17c9 Update README.md 2016-05-06 17:18:01 +02:00
Aurora
9d68c980e6 Added support for 9.5 New 3DS FIRM to the arm9loader 2016-05-05 04:43:44 +02:00
Aurora
17d3c6491a Cleanup, removed redundant file reading code 2016-05-03 20:03:37 +02:00
Aurora
905f816bbe Get rid of the double FatFs 2016-05-03 03:17:00 +02:00
Aurora
fef48a449a Code refactoring, added support for SAFE_MODE FIRM on A9LH (you can update safely from it now). Thanks to delebile for the O3DS SAFE_MODE FIRM FIRM0/1 protection! 2016-05-03 01:21:43 +02:00
Aurora
95d06c115a Fixed crashes loading an emuNAND if the SD was too small to be able to hold it 2016-05-02 02:07:23 +02:00
Aurora
113059e57c Fixed L+R booting the updated NAND with the FIRM from the outdated NAND 2016-05-01 19:48:59 +02:00
Aurora
5b51574ebf We do not need all that space anymore 2016-04-30 03:34:28 +02:00
Aurora
df112b550b Move loadPayload to fs.c, and the path to the beginning of the chainloader 2016-04-29 17:22:13 +02:00
Aurora
85615d1916 Fix external FIRM loading 2016-04-29 15:21:49 +02:00
Aurora
c6d3158b56 Remade the chainloader to only try to load the right payload for the pressed button, got rid of the default payload (start now boots "start_NAME.bin"), sel_NAME is now select_NAME as there is no more SFN limitations anymore 2016-04-29 15:08:33 +02:00
Aurora
e651c3d9cc Small cleanup 2016-04-28 16:27:32 +02:00
Aurora
bfc2448662 Simplify makefiles 2016-04-28 00:43:25 +02:00
Aurora
5a9d0e2569 Fail 2016-04-27 16:16:25 +02:00
Aurora
041ca8451e Use the older cxi, should fix NANDs with incomplete background updates 2016-04-27 15:37:13 +02:00
Aurora
2382e6d82c Fixed oversight in the injector 2016-04-27 04:52:23 +02:00
Aurora
f9a1f1a79b Move the UNITINFO patch to the developer version 2016-04-26 21:51:57 +02:00
Aurora
a736e4602a Cleanup 2016-04-26 20:10:20 +02:00
Aurora
5202ba8826 Update ReadME 2016-04-26 14:33:01 +02:00
Aurora
0f1bc98bb7 Rename "Use SysNAND FIRM as default" to "SysNAND is updated" 2016-04-26 14:11:34 +02:00
Aurora
d40722af53 Apply the eShop update skipping patch only if the updated NAND was not booted (depends on the "Use SysNAND FIRM as default" option) 2016-04-26 14:05:48 +02:00
Aurora
c9781ab626 Added python implementation of the path changer from @TuxSH 2016-04-26 03:39:36 +02:00
Aurora
4cbf4e93e7 Minor stuff 2016-04-26 01:30:03 +02:00
Aurora
1f68c2da42 Update ReadME 2016-04-24 20:19:35 +02:00
Aurora
d786c292f3 Update submodules 2016-04-24 19:49:09 +02:00
Aurora
ada3e09784 Added L+A payload 2016-04-24 19:46:33 +02:00
Aurora
c928b3b68b New icon 2016-04-23 15:39:40 +02:00
Aurora
ae9c29629c Wrong name in the Makefile 2016-04-23 03:50:04 +02:00
Aurora
3fd4603553 Welcome Luma3DS 2016-04-23 01:43:36 +02:00
Aurora
c14526068a Minor stuff 2016-04-21 23:39:05 +02:00
Aurora
180b2a6f4d Bye bye fileSize! 2016-04-21 05:08:42 +02:00
Aurora
b926ab7dd2 Give 3ds_injector a sane makefile 2016-04-20 03:31:40 +02:00
Aurora
19d8861d27 Give 3ds_injector a sane makefile 2016-04-19 20:51:00 +02:00
Aurora
70e82e627b More cleanup 2016-04-19 17:28:18 +02:00
Aurora
67e229e5a9 Cleanup of the injector 2016-04-18 23:14:35 +02:00
Aurora
d0d6baaa85 We do not need this anymore (D9/E9/GM9 were updated) 2016-04-18 18:52:58 +02:00
Aurora
fd4352a1d6 Remove useless sdmmc code (we do not need NAND init/read from loader, or write at all 2016-04-18 18:29:37 +02:00
Aurora
08808da741 Update FatFs to 0.12 2016-04-18 18:04:04 +02:00
Aurora
a11124a3d6 Remove LFN support from the loader FatFs as it is not used. Slims down the binary by ~4 KBs 2016-04-18 04:47:53 +02:00
Aurora
d2d6e786c7 Fixed L+SELECT payload being broken (annoying LFN to 8.3 conversion rules). Now the payload is sel_NAME.bin 2016-04-18 02:55:54 +02:00
Aurora
a76c943c01 Reinstated the L+SELECT payload 2016-04-17 19:35:29 +02:00
Aurora
3c64a3a234 Updated ReadME 2016-04-17 19:11:38 +02:00
Aurora
06060c67b5 Changed the chainloader to load payloads named "BUTTON_NAME.bin", to remember which payload is which. Original idea and code by @habbbe (many thanks!) 2016-04-17 18:57:25 +02:00
Aurora
0f64fd73ec Fix bug when quitting AGB_FIRM
The wrong config.bin section was used to remember the last-used FIRM
2016-04-16 20:27:52 +02:00
Aurora
2323528975 Merge pull request #29 from habbbe/master
Made define for payload paths (removes repeated parts of file paths t…
2016-04-16 18:39:22 +02:00
habbbe
22b38a0f88 Made define for payload paths (removes repeated parts of file paths to payloads) 2016-04-16 18:21:42 +02:00
Aurora
034c0f8d7c Updated ReadME 2016-04-15 19:46:25 +02:00
Aurora
b4cd67cb8c Merge pull request #24 from ericchu94/master
Fix buffer overflow due to null character
2016-04-15 19:32:10 +02:00
Eric Chu
be83d77187 Fix buffer overflow due to null character 2016-04-15 12:54:30 -04:00
Aurora
615cf81a9f Further compatibility fix for language/region emulation, now works with games like Kirby Triple Deluxe 2016-04-15 17:54:45 +02:00
Aurora
c60ef7fe82 Better to reboot here 2016-04-15 16:10:32 +02:00
Aurora
fea5a111a9 Misc fixes, renamed "Updated SysNAND" to reflect what the option actually does now 2016-04-15 16:01:44 +02:00
Aurora
7eebfd4f6a Added improved language emulation from @TuxSH (improves compatibility), fixed language emulation only working for the first launched game/app and not being applied on demos 2016-04-15 03:34:08 +02:00
Aurora
939965b5a0 Cleanup 2016-04-14 17:10:55 +02:00
Aurora
a0334120a6 Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:59:14 +02:00
Aurora
308417a48e Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:56:34 +02:00
Aurora
85533411c9 Config menu cleanup 2016-04-13 15:29:44 +02:00
Aurora
6d4a84a325 Remove unneeded stuff from the loader injection 2016-04-13 14:37:40 +02:00
Aurora
89350b1edd Fixed config.bin getting recreated on each boot 2016-04-13 04:18:59 +02:00
Aurora
9e58e4ed7a Screwed up the order of the CPU settings 2016-04-13 00:36:35 +02:00
Aurora
f8f4ecea27 Add better code to the FIRM finding function to convert from integer to its hex representation array 2016-04-13 00:20:28 +02:00
Aurora
e9449f86bf Rewrote config menu to allow for multiple choice settings, made the N3DS CPU patch configurable in the NTR way, changed the config.bin format to be more future-proof (settings are on the leftmost part), added more macros to read settings 2016-04-12 23:28:35 +02:00
Aurora
4fabe1f704 Added new and working N3DS CPU patch from @TuxSH 2016-04-12 15:25:36 +02:00
Aurora
ef3ba896d5 Cleanup, removed the non-working clock speed patch 2016-04-12 14:32:38 +02:00
Aurora
649b160292 Use better makefiles for loader and the screen init stub 2016-04-12 04:55:36 +02:00
Aurora
697bc74535 Added tentative N3DS clock speed/L2 cache patch by @TuxSH. 2016-04-12 01:22:42 +02:00
Aurora
0e9ff44746 Made N3DS >9.6 key generation version independent 2016-04-11 22:26:39 +02:00
Aurora
49d49e637a Merge pull request #20 from Steveice10/master
Add developer UNITINFO patch.
2016-04-11 21:17:22 +02:00
Steven Smith
b3f0d13aa4 Add developer UNITINFO patch. 2016-04-11 12:14:51 -07:00
Aurora
bd1547710e Derp 2016-04-11 18:43:51 +02:00
Aurora
7479bf8092 Fixed possible issue with the injector 2016-04-11 18:08:22 +02:00
Aurora
d4d281bb9c Removed debug info patch 2016-04-11 17:14:00 +02:00
Aurora
68bf134017 Merge pull request #19 from TuxSH/master
"Friends" and "ErrDisp" patches (and Makefile fix)
2016-04-11 16:46:12 +02:00
Aurora
c7b90f739f Use fLTO to reduce the binary size 2016-04-11 15:58:58 +02:00
Aurora
160bc36ae8 Update FatFs for the loader 2016-04-11 15:13:05 +02:00
Aurora
464bf1680c Small changes 2016-04-11 14:42:34 +02:00
TuxSH
c51eaba18c Revert "Update FatFs"
This reverts commit 6d06ea6975.
2016-04-11 11:46:49 +02:00
Aurora
7dbded99a2 First commit of the AuReiNand rewrite!
- Gotten rid of the patched FIRMs, AuReiNand now finds and loads all the FIRMs from CTRNAND by default. If you are booting an emuNAND, the FIRMs will be loaded from its CTRNAND. This also applies to AGB and TWL FIRM, and allows for a very fast boot with no firmware files on the SD card.
- If for some reason (like using NTR) you do not want to use the CTRNAND FIRM, you can place a firmware.bin in the aurei folder and it will be loaded just for the default NAND.
- The way AuReiNand works has changed. Now you can specify to autoboot SysNAND or not, and a NAND is no more tied to a FIRM (since 9.0 FIRM is autodetected). If you press nothing the default NAND is booted with its own FIRM, L boots the non-default NAND with its own FIRM, R boots EmuNAND with the SysNAND FIRM if you picked "Updated SysNAND", and vice-versa.
- In order for AuReiNand to handle FIRM reboots, the .bin path needs to be hardcoded in the program. The default is /arm9loaderhax.bin (the AuReiNand.dat is also supported for 9.0 people). A PC tool was written to make changing the path easier.
- Bug fixes and stuff I forgot.
- Gelex is a saint.
2016-04-11 05:58:46 +02:00
TuxSH
6351e5b8c3 Implement "friends" and "ErrDisp" patches 2016-04-08 23:28:40 +02:00
TuxSH
5a0f2e4dfc Fix Makefile (by including 3ds_rules) 2016-04-08 19:52:37 +02:00
Aurora
6d06ea6975 Update FatFs 2016-04-07 17:16:57 +02:00
Aurora
4180261f1f Small changes, added a macro for reading options 2016-04-06 14:54:58 +02:00
Aurora
e882dd7aaf Rewrote the config menu (no longer prints the whole menu on each button press), cleaned up the reboot patch, boot options will keep being forced if a GBA game was lanched from SysNAND, added option to have a splash screen with the built-in screen-init 2016-04-05 23:20:21 +02:00
Aurora
9e851d2dfd Small code reorganization 2016-04-05 05:34:57 +02:00
Aurora
21a3edb150 Get rid of double options reading 2016-04-05 03:08:38 +02:00
Aurora
3aacbd17ce Upped patch version 2016-04-05 02:29:36 +02:00
Aurora
6f8a9421ef Added basic support for configuring the brightness level for the built-in screen init 2016-04-05 02:24:21 +02:00
Aurora
bb437f6f7b Better commenting 2016-04-04 19:14:49 +02:00
Aurora
0001f301f8 Cleanup, fixed the second emuNAND patched FIRM still getting created, removed injector SOAP patch as it changes nothing without going to great lengths to change the region of a NNID, made L not needed to load payloads except for R and Select (Start is now default) 2016-04-04 18:07:13 +02:00
Aurora
f7bbc4bfec Made the AGB_FIRM splash screen optional
Apparently it causes compatibility issues
2016-04-04 01:08:42 +02:00
Aurora
a127a38438 Updated ReadME 2016-04-03 19:53:03 +02:00
Aurora
16225b97d7 Small changes 2016-04-03 18:18:44 +02:00
Aurora
0587c14162 Forgot stuff 2016-04-03 18:10:48 +02:00
Aurora
a181bba9f2 Added TWL/AGB FIRM patching/SD loading for New and Old 3DS (thanks to mid-kid of CakesFW for making it possible!) 2016-04-03 17:56:09 +02:00
Aurora
993e564fbb u32-ify 2016-04-02 22:02:16 +02:00
Aurora
956829864c This looks unused (my AUS N3DS has 2) 2016-04-02 18:57:52 +02:00
Aurora
24186a7148 Some more tidying up 2016-04-02 18:48:31 +02:00
Aurora
3475cfe1e6 Changed indentation style across the code to make it more readable, added newlines before comments, moved patches to separate functions, made memory operations slightly faster by compiling them with O3 (thanks TuxSH!) 2016-04-02 18:22:47 +02:00
Aurora
6b64a10362 Fixed ARM11 access to chainloaded payloads 2016-04-01 14:27:31 +02:00
Aurora
5e99fb3aa0 Fixed dumb mistakes 2016-03-31 18:25:50 +02:00
Aurora
060d8e9945 Comment things better 2016-03-31 16:04:12 +02:00
Aurora
1026471842 Leftover from testing 2016-03-31 15:59:40 +02:00
Aurora
645208ec82 EmuNAND is detected almost instantly when the CFW configures itself, if the user is attempting to load an EmuNAND and none is found, SysNAND and 9.6/10.x FIRM are forced. Also prevents the second EmuNAND patched FIRM from being created if no second EmuNAND exists. 2016-03-31 15:57:02 +02:00
Aurora
f4c48a64ca Fixed loading the alternate EmuNAND if 9.0 FIRM was set as default, improved comments and further cleanup of the injector 2016-03-31 01:38:28 +02:00
Aurora
c80ac985fe Further clean-up of the patcher code 2016-03-29 22:43:15 +02:00
Aurora
ac9bdc7665 Fixed exiting GBA games with updated SysNAND 2016-03-29 18:56:51 +02:00
Aurora
217d75024d These should be u32s 2016-03-29 18:47:30 +02:00
Aurora
12e5b4adb9 Updated readME 2016-03-29 18:17:22 +02:00
Aurora
945f80993b Zero the last-FIRM-booted flag when exiting config 2016-03-29 17:58:33 +02:00
Aurora
5f32779ceb Lots of changes/new features
- To override the last used boot mode on soft reboot, you only need to press A if you want to boot to the default option. Holding L(+payload button)/R is enough for the other modes.
- Added version number to the config menu
- Replaced the memsearch algorithm with a faster one
- Integrated 3ds_injector from @yifanlu. This brings us region free and all the other FreeMultiPatcher patches. Other than that, you now have the possibility to display the currently booted NAND/FIRM in System Settings!
- Rewritten most code for the config menu. You now can navigate to the first/last options with left and right.
- You can now choose the 9.0 FIRM to be default in the config menu. This will essentially switch "no buttons" and L in both modes.
- You can now choose the second emuNAND to be default in the config menu. This will essentially switch "B is not pressed" and "B is pressed".
- When the second emuNAND is booted, it will persist like the other boot options on soft reboot
- Bugfixes
2016-03-29 17:43:53 +02:00
Aurora
e8ebb2f7fe Fixed signature patterns searching area, aligned variable/function names to the latest ReiNand 2016-03-27 19:19:35 +02:00
Aurora
034e63669a Readability 2016-03-27 18:47:08 +02:00
Aurora
c75ed567fc Added version number to the config menu 2016-03-27 18:39:16 +02:00
Aurora
1e2bf61dcf Possibly makes FatFs faster, does not affect loader size much 2016-03-27 16:42:19 +02:00
Aurora
de4fea77a1 Make the code more readable by defining variables locally, avoid useless redefinitions, when rebooting from TWL and NATIVE_FIRM you can now override with just A (same as pressing nothing), L(+payload buttons) or R 2016-03-27 16:31:05 +02:00
Aurora
441c143b3e No reason for these not to be u8s 2016-03-26 19:28:46 +01:00
Aurora
feff28a4fe Added multi redNAND support (thanks to @Desterly for the original commit) 2016-03-26 17:48:12 +01:00
Aurora
b3d25ce64a Better commenting 2016-03-26 17:28:47 +01:00
Aurora
0f44205959 Simplified patching, yet one memsearch less, fixed override with A+L when boot options are forced 2016-03-26 17:25:05 +01:00
Aurora
1861d556a6 Spaces and stuff
Makes things more uniform
2016-03-25 18:17:12 +01:00
Aurora
9b1df43687 Useless casts again 2016-03-25 01:58:42 +01:00
Aurora
56e0157d64 Forgot about MCU reboots 2016-03-24 17:33:32 +01:00
Aurora
d23cd5acd5 More logical this way 2016-03-24 17:24:16 +01:00
Aurora
39a9eb5ccb Explicitly block Safe Mode access on A9LH
Prevents bricking
2016-03-24 17:05:19 +01:00
Aurora
c413b6d07f Simplified button stuff 2016-03-24 16:11:53 +01:00
Aurora
85a59264c9 Comment 2016-03-24 02:40:43 +01:00
Aurora
7f96e47b4f Updated sysNAND (A9LH) & SAFE_MODE FIRM update = brick 2016-03-24 02:26:04 +01:00
Aurora
02b5c69802 New way of launching payloads (L+R/up/down/right/left/START/SELECT/B/X/Y) 2016-03-24 01:57:56 +01:00
Aurora
b5eb108393 Increased the screen-init brightness 2016-03-24 00:11:02 +01:00
Aurora
0a9cd09cc3 Reorganized folder layout, cleaned Makefile (we do not need Python) 2016-03-23 20:29:19 +01:00
Aurora
af451b4997 Update submodules 2016-03-23 17:51:21 +01:00
Aurora
a5f8ccc3ea Fixed loader.bin not cleared after compiling 2016-03-23 17:09:52 +01:00
Aurora
28cdcfed9c Updated ReadMe 2016-03-23 17:00:18 +01:00
Aurora
ea3e45d40a Move clearScreens calls and screen-init checks 2016-03-23 16:14:28 +01:00
Aurora
8daf3ebe3f Detect emuNAND first 2016-03-23 15:52:21 +01:00
Aurora
7ad55ed61e Chainloading works from CakeBrah too, by now 2016-03-23 15:26:52 +01:00
Aurora
96e46b2234 Remove unneeded casts 2016-03-23 15:16:40 +01:00
Aurora
094b88b6aa Forgot this 2016-03-23 15:03:14 +01:00
Aurora
03a6e343db Merge emunand.bin, reboot.bin and loader.bin in the main executable
Less SD accesses, more noob-proof
2016-03-23 15:00:28 +01:00
Aurora
b42f9ffb41 Warn that Updated SysNAND does not work if not using A9LH 2016-03-23 04:56:02 +01:00
Aurora
39280e397a Fix typo 2016-03-23 04:27:07 +01:00
Aurora
887707ea87 Better errors 2016-03-23 04:06:21 +01:00
Aurora
279f39bc13 Added error messages, moved emunand and reboot.bin to aurei/patches 2016-03-23 03:46:44 +01:00
Aurora
b7b734bad1 Added configuration menu (thanks to Cakes for the screen printing code - no more flags!), auto-delete of patched FIRMs when switching to/from A9LH or the CFW gets updated, moved screen init from the loader, general reorganization 2016-03-23 02:46:41 +01:00
Aurora
d01d9b53f2 No need to search for the Process9 .code, calculate it (one memsearch less) 2016-03-21 20:27:01 +01:00
Aurora
c542bc5cf3 More readable this way 2016-03-21 19:20:26 +01:00
Aurora
1f5b824c27 Clean-up, optimized the SDMMC struct searching function, lots of useless casts removed, Process9 only gets searched once 2016-03-21 19:14:32 +01:00
Aurora
cb84a6c7ea Added interrupts disabling to the deinit function
Did not cause any issues, but it is better this way
2016-03-21 04:58:20 +01:00
Aurora
61564e5fcf Check for emuNAND earlier 2016-03-21 04:39:00 +01:00
Aurora
a437e533f5 Slightly improved the reboot patch, added emuNAND patch improvements from CakesFW, made the emuNAND patch completely version-independent
Should work as-is with future firmwares!
2016-03-21 03:21:22 +01:00
Aurora
6b88953517 Moved D9 launching fix to the loader 2016-03-20 22:03:43 +01:00
Aurora
9b9f784c26 Fixed intermittent splash from CakeBrah, made splash last slightly longer, added shutdown on error, slimmed down FatFs, added error on missing emuNAND, changed folder to "aurei", changed the dat name to "AuReiNand.dat", propered the built-in screen init of the chainloader, remade the look of the 3dsx
(First luma-powered CFW!)
2016-03-20 17:38:45 +01:00
Aurora
6dfb33191f Minor changes 2016-03-17 04:51:07 +01:00
Aurora
078fce4b3d Better here 2016-03-17 00:37:43 +01:00
Aurora
dcb09a9472 Added dual emuNAND support, multi-payload loader with built-in screen init (inspired by arm9select, thanks Fix94) 2016-03-17 00:15:38 +01:00
Aurora
8ce395caa5 Switch to Normmatt's iodelay
Seems to be more reliable in all conditions
2016-03-16 04:01:38 +01:00
Aurora
e9410c86b1 Added RedNAND support (untested) 2016-03-14 14:51:30 +01:00
Aurora
42885560ed Some clean-up 2016-03-13 17:01:00 +01:00
Aurora
796e4dd060 Forgot this 2016-03-13 04:03:07 +01:00
Aurora
9468582d83 Clean-up, fixed mistake
GCC, why no u warn me of strict aliasing
2016-03-12 15:48:20 +01:00
Aurora
6707a36ffe Minor changes 2016-03-10 16:06:44 +01:00
Aurora
09cc7c903c Oops #2 2016-03-10 04:25:38 +01:00
Aurora
9be7481c14 Minor formatting updates 2016-03-10 03:06:44 +01:00
Aurora
9f68ce0d70 Oops 2016-03-10 01:59:25 +01:00
Aurora
4748c0292c Added bottom screen splash image support
As suggested by Apache Thunder
2016-03-10 01:31:39 +01:00
Aurora
c3ebce1666 Crush loader warnings 2016-03-09 15:09:46 +01:00
Aurora
b1a428f6bc Disable splash screen when forcing boot options 2016-03-09 14:59:20 +01:00
Aurora
3e0b928db0 Not needed 2016-03-08 15:45:04 +01:00
Aurora
09380a19ff External ARM9 payload chainloading for a9lh, cleaned up the sdmmc library (from the dark-samus a9lh fork) 2016-03-08 15:29:25 +01:00
Aurora
04978ebb01 Const for all
Probably useless, but for the sake of readability
2016-03-06 23:52:14 +01:00
Aurora
478ebeadf8 Fixed stupid mistakes 2016-03-06 19:05:41 +01:00
Aurora
13fd33a61d Switched to 32-bit variables when possible, removed unneeded casts
Thanks @Fix94 for the tip
2016-03-06 18:29:47 +01:00
Aurora
4bdba9f8e9 Even moar clean-up 2016-03-06 16:31:16 +01:00
Aurora
99829b3cf7 (Hopefully last) clean-up 2016-03-06 05:04:28 +01:00
Aurora
d4a3ce2d0d Clean-up of the filesystem functions 2016-03-05 23:33:11 +01:00
Aurora
a58cb05f2c Previous release broke .dat booting from a 9.0 NAND if A9LH was installed
Also, more clean-up
2016-03-05 20:22:31 +01:00
Aurora
9ab6d107b4 Not needed 2016-03-05 18:47:47 +01:00
Aurora
42cbead456 Remove redundancies 2016-03-05 16:16:25 +01:00
Aurora
90ebe78c8e Added forcing of boot options on A9LH
Always prevents losing AGB_FIRM saves, forces the last used options on a MCU reboot (can be overridden with A)
2016-03-05 15:42:40 +01:00
Aurora
bf81ec252e Even more clean-up 2016-03-05 00:56:35 +01:00
Aurora
899ad1887a Some clean-up 2016-03-05 00:41:42 +01:00
Aurora
cb06cf83ff Added flag to use a pre-patched FIRM (skips all decrypting and patching)
Original patch by @Fix94
2016-03-05 00:01:54 +01:00
Aurora
aede5a5331 Not needed 2016-03-02 04:33:20 +01:00
Aurora
5a41663ddc Minor splash fixes 2016-03-02 00:49:14 +01:00
Aurora
7f6ef45f37 Avoid overflows with menuhax generated splashes 2016-02-29 17:01:16 +01:00
Aurora
32e2b85f3a Get up-to-date with official build 2016-02-29 16:28:43 +01:00
Aurora
6fe748f58c Not needed 2016-02-28 16:20:06 +01:00
Aurora
e74eda16ce Fixed reboot patch on N3DS
Yay, 178 MB content!
2016-02-26 02:48:42 +01:00
86 changed files with 14170 additions and 7724 deletions

10
.gitignore vendored
View File

@@ -1,12 +1,12 @@
out out
CakeHax
CakeBrah
build build
data loader/build
injector/build
exceptions/arm9/build
exceptions/arm11/build
*.bin *.bin
*.3dsx *.3dsx
*.smdh *.smdh
*.o *.o
*.d *.d
*.elf *.elf
*.bat

Submodule CakeHax updated: 6b8fca0b37...5245c7b9dc

139
Makefile
View File

@@ -1,107 +1,126 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc CC := arm-none-eabi-gcc
AS := arm-none-eabi-as AS := arm-none-eabi-as
LD := arm-none-eabi-ld LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy OC := arm-none-eabi-objcopy
OPENSSL := openssl
PYTHON3 := python name := Luma3DS
PYTHON_VER_MAJOR := $(word 2, $(subst ., , $(shell python --version 2>&1))) revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
ifneq ($(PYTHON_VER_MAJOR), 3) commit := $(shell git rev-parse --short=8 HEAD)
PYTHON3 := py -3
endif
name := ReiNand
dir_source := source dir_source := source
dir_data := data dir_patches := patches
dir_build := build dir_loader := loader
dir_injector := injector
dir_mset := CakeHax dir_mset := CakeHax
dir_out := out
dir_emu := emunand
dir_reboot := reboot
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
dir_build := build
dir_out := out
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) --no-print-directory LDFLAGS := -nostartfiles
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Aurora Wright/TuxSH" --no-print-directory
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c))) $(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/svcGetCFWInfopatch.h $(dir_build)/twl_k11modulespatch.h \
$(dir_build)/injector.h $(dir_build)/loader.h
.PHONY: all .PHONY: all
all: launcher a9lh emunand reboot ninjhax all: launcher a9lh ninjhax
.PHONY: launcher .PHONY: launcher
launcher: $(dir_out)/$(name).dat launcher: $(dir_out)/$(name).dat
.PHONY: a9lh .PHONY: a9lh
a9lh: $(dir_out)/arm9loaderhax.bin a9lh: $(dir_out)/arm9loaderhax.bin
.PHONY: emunand
emunand: $(dir_out)/rei/emunand/emunand.bin
.PHONY: reboot
reboot: $(dir_out)/rei/reboot/reboot.bin
.PHONY: ninjhax .PHONY: ninjhax
ninjhax: $(dir_out)/3ds/$(name) ninjhax: $(dir_out)/3ds/$(name)
.PHONY: release
release: $(dir_out)/$(name)$(revision).7z
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
rm -rf $(dir_out) $(dir_build) @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build)
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei $(dir_out):
@mkdir -p "$(dir_out)"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher @$(MAKE) $(FLAGS) -C $(dir_mset) launcher
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)/rei $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $(dir_out)/arm9loaderhax.bin @cp -a $(dir_build)/main.bin $@
$(dir_out)/3ds/$(name): $(dir_out)/3ds/$(name): $(dir_out)
@mkdir -p "$(dir_out)/3ds/$(name)" @mkdir -p "$@"
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) @$(MAKE) $(FLAGS) -C $(dir_ninjhax)
@mv $(dir_out)/$(name).3dsx $@ @mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
@mv $(dir_out)/$(name).smdh $@
$(dir_out)/rei: $(dir_out)/$(name)$(revision).7z: launcher a9lh ninjhax
@mkdir -p "$(dir_out)/rei" @7z a -mx $@ ./$(@D)/*
$(dir_out)/rei/emunand/emunand.bin: $(dir_emu)/emuCode.s
@armips $<
@mkdir -p "$(dir_out)/rei/emunand"
@mv emunand.bin $(dir_out)/rei/emunand
$(dir_out)/rei/reboot/reboot.bin: $(dir_reboot)/rebootCode.s
@armips $<
@mkdir -p "$(dir_out)/rei/reboot"
@mv reboot.bin $(dir_out)/rei/reboot
$(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@ $(OC) -S -O binary $< $@
$(dir_build)/main.elf: $(objects_cfw) $(dir_build)/main.elf: $(objects)
# FatFs requires libgcc for __aeabi_uidiv $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/emunandpatch.h: $(dir_patches)/emunand.s $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@armips $<
@bin2c -o $@ -n emunand $(@D)/emunand.bin
$(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
@mkdir -p "$(@D)"
@armips $<
@bin2c -o $@ -n reboot $(@D)/reboot.bin
$(dir_build)/svcGetCFWInfopatch.h: $(dir_patches)/svcGetCFWInfo.s
@mkdir -p "$(@D)"
@armips $<
@bin2c -o $@ -n svcGetCFWInfo $(@D)/svcGetCFWInfo.bin
$(dir_build)/twl_k11modulespatch.h: $(dir_patches)/twl_k11modules.s
@mkdir -p "$(@D)"
@armips $<
@bin2c -o $@ -n twl_k11modules $(@D)/twl_k11modules.bin
$(dir_build)/injector.h: $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@$(MAKE) -C $(dir_injector)
@bin2c -o $@ -n injector $(@D)/injector.cxi
$(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@bin2c -o $@ -n loader $(@D)/loader.bin
$(dir_build)/memory.o: CFLAGS += -O3
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s $(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $< $(COMPILE.s) $(OUTPUT_OPTION) $<
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $<
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d) include $(call rwildcard, $(dir_build), *.d)

View File

@@ -1,24 +1,23 @@
# AuReiNand # Luma3DS
*A modification of the ReiNand custom firmware* *Noob-proof (N)3DS "Custom Firmware"*
**Compiling:** **Compiling:**
You'll need armips added to your Path. [HERE](https://www.dropbox.com/s/ceuv2qeqp38lpah/armips.exe?dl=0) is a pre-compiled version. First you need to clone the repository recursively with: `git clone --recursive https://github.com/AuroraWright/Luma3DS.git`
To compile, you'll need [armips](https://github.com/Kingcom/armips), [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH.
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!).
Finally just run `make` and everything should work!
You can find the compiled files in the 'out' folder.
Lastly, just run Make and everything should work! **Setup / Usage / Features:**
Copy everything in 'out' folder to SD root and run! See https://github.com/AuroraWright/Luma3DS/wiki
**Usage / Features:**
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
The FIRMs you need are here:
http://www99.zippyshare.com/v/kEIiQl0x/file.html
**Credits:** **Credits:**
Rei as this is 99% his code (this is no more than a mod) See https://github.com/AuroraWright/Luma3DS/wiki/Credits
Everyone he credited on his GitHub :P **Licensing:**
This software is licensed under the terms of the GPLv3.
You can find a copy of the license in the LICENSE.txt file.

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

21
injector/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Yifan Lu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

51
injector/Makefile Executable file
View File

@@ -0,0 +1,51 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
LIBS := -lctru
LIBDIRS := $(CTRULIB)
LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ARCH)
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.c))
.PHONY: all
all: ../$(dir_build)/$(name).cxi
.PHONY: clean
clean:
@rm -rf $(dir_build)
../$(dir_build)/$(name).cxi: $(dir_build)/$(name).elf
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
$(dir_build)/$(name).elf: $(objects)
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
$(dir_build)/memory.o : CFLAGS += -O3
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

30
injector/README.md Normal file
View File

@@ -0,0 +1,30 @@
3DS Loader Replacement
======================
This is an open source implementation of 3DS `loader` system module--with
additional features. The current aim of the project is to provide a nice
entry point for patching 3DS modules.
## Roadmap
Right now, this can serve as an open-source replacement for the built in loader.
There is additional support for patching any executable after it's loaded but
before it starts. For example, you can patch `menu` to skip region checks and
have region free game launching directly from the home menu. There is also
support for SDMC reading (not found in original loader implementation) which
means that patches can be loaded from the SD card. Ultimately, there would be
a patch system that supports easy loading of patches from the SD card.
## Build
You need a working 3DS build environment with a fairly recent copy of devkitARM,
ctrulib, and makerom. If you see any errors in the build process, it's likely
that you're using an older version.
Currently, there is no support for FIRM building, so you need to do some steps
manually. First, you have to add padding to make sure the NCCH is of the right
size to drop in as a replacement. A hacky way is
[this patch](http://pastebin.com/nyKXLnNh) which adds junk data. Play around
with the size value to get the NCCH to be the exact same size as the one
found in your decrypted FIRM dump.
Once you have a NCCH of the right size, just replace it in your decrypted FIRM
and find a way to launch it (for example with ReiNAND).

115
injector/loader.rsf Normal file
View File

@@ -0,0 +1,115 @@
BasicInfo:
Title : loader
CompanyCode : "00"
ProductCode : 0828builder
ContentType : Application
Logo : None
TitleInfo:
UniqueId : 0x13
Category : Base
Version : 2
Option:
UseOnSD : false
FreeProductCode : true # Removes limitations on ProductCode
MediaFootPadding : false # If true CCI files are created with padding
EnableCrypt : false # Enables encryption for NCCH and CIA
EnableCompress : true # Compresses exefs code
AccessControlInfo:
IdealProcessor : 1
AffinityMask : 3
Priority : 20
DisableDebug : true
EnableForceDebug : false
CanWriteSharedPage : false
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : false
PermitMainFunctionArgument : false
CanShareDeviceMemory : false
RunnableOnSleep : true
SpecialMemoryArrange : true
ResourceLimitCategory : Other
CoreVersion : 2
DescVersion : 2
MemoryType : Base # Application / System / Base
HandleTableSize: 0
SystemCallAccess:
AcceptSession: 74
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateCodeSet: 115
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreatePort: 71
CreateProcess: 117
CreateSemaphore: 21
CreateSessionToPort: 72
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdealProcessor: 6
GetProcessIdOfThread: 54
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
RandomStub: 116
ReleaseMutex: 20
ReleaseSemaphore: 22
ReplyAndReceive1: 75
ReplyAndReceive2: 76
ReplyAndReceive3: 77
ReplyAndReceive4: 78
ReplyAndReceive: 79
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
ServiceAccessControl:
- fs:LDR
FileSystemAccess:
- DirectSdmc
- CtrNandRw
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 0
StackSize: 0x1000

97
injector/source/exheader.h Executable file
View File

@@ -0,0 +1,97 @@
#pragma once
#include <3ds/types.h>
typedef struct
{
u8 reserved[5];
u8 flag;
u8 remasterversion[2];
} PACKED exheader_systeminfoflags;
typedef struct
{
u32 address;
u32 nummaxpages;
u32 codesize;
} PACKED exheader_codesegmentinfo;
typedef struct
{
u8 name[8];
exheader_systeminfoflags flags;
exheader_codesegmentinfo text;
u8 stacksize[4];
exheader_codesegmentinfo ro;
u8 reserved[4];
exheader_codesegmentinfo data;
u32 bsssize;
} PACKED exheader_codesetinfo;
typedef struct
{
u64 programid[0x30];
} PACKED exheader_dependencylist;
typedef struct
{
u8 savedatasize[4];
u8 reserved[4];
u8 jumpid[8];
u8 reserved2[0x30];
} PACKED exheader_systeminfo;
typedef struct
{
u8 extsavedataid[8];
u8 systemsavedataid[8];
u8 reserved[8];
u8 accessinfo[7];
u8 otherattributes;
} PACKED exheader_storageinfo;
typedef struct
{
u64 programid;
u8 flags[8];
u16 resourcelimitdescriptor[0x10];
exheader_storageinfo storageinfo;
u64 serviceaccesscontrol[0x20];
u8 reserved[0x1f];
u8 resourcelimitcategory;
} PACKED exheader_arm11systemlocalcaps;
typedef struct
{
u32 descriptors[28];
u8 reserved[0x10];
} PACKED exheader_arm11kernelcapabilities;
typedef struct
{
u8 descriptors[15];
u8 descversion;
} PACKED exheader_arm9accesscontrol;
typedef struct
{
// systemcontrol info {
// coreinfo {
exheader_codesetinfo codesetinfo;
exheader_dependencylist deplist;
// }
exheader_systeminfo systeminfo;
// }
// accesscontrolinfo {
exheader_arm11systemlocalcaps arm11systemlocalcaps;
exheader_arm11kernelcapabilities arm11kernelcaps;
exheader_arm9accesscontrol arm9accesscontrol;
// }
struct {
u8 signature[0x100];
u8 ncchpubkeymodulus[0x100];
exheader_arm11systemlocalcaps arm11systemlocalcaps;
exheader_arm11kernelcapabilities arm11kernelcaps;
exheader_arm9accesscontrol arm9accesscontrol;
} PACKED accessdesc;
} PACKED exheader_header;

109
injector/source/fsldr.c Normal file
View File

@@ -0,0 +1,109 @@
#include <3ds.h>
#include "fsldr.h"
#include "fsreg.h"
#include "srvsys.h"
#define SDK_VERSION 0x70200C8
static Handle fsldrHandle;
static int fsldrRefCount;
// MAKE SURE fsreg has been init before calling this
static Result fsldrPatchPermissions(void)
{
u32 pid;
Result res;
FS_ProgramInfo info;
u32 storage[8] = {0};
storage[6] = 0x680; // SDMC access and NAND access flag
info.programId = 0x0004013000001302LL; // loader PID
info.mediaType = MEDIATYPE_NAND;
res = svcGetProcessId(&pid, 0xFFFF8001);
if (R_SUCCEEDED(res))
{
res = FSREG_Register(pid, 0xFFFF000000000000LL, &info, (u8 *)storage);
}
return res;
}
Result fsldrInit(void)
{
Result ret = 0;
if (AtomicPostIncrement(&fsldrRefCount)) return 0;
ret = srvSysGetServiceHandle(&fsldrHandle, "fs:LDR");
if (R_SUCCEEDED(ret))
{
fsldrPatchPermissions();
ret = FSLDR_InitializeWithSdkVersion(fsldrHandle, SDK_VERSION);
ret = FSLDR_SetPriority(0);
if (R_FAILED(ret)) svcBreak(USERBREAK_ASSERT);
}
else
{
AtomicDecrement(&fsldrRefCount);
}
return ret;
}
void fsldrExit(void)
{
if (AtomicDecrement(&fsldrRefCount)) return;
svcCloseHandle(fsldrHandle);
}
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x861,1,2); // 0x8610042
cmdbuf[1] = version;
cmdbuf[2] = 32;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(session))) return ret;
return cmdbuf[1];
}
Result FSLDR_SetPriority(u32 priority)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x862,1,0); // 0x8620040
cmdbuf[1] = priority;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
return cmdbuf[1];
}
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x803,8,4); // 0x8030204
cmdbuf[1] = 0;
cmdbuf[2] = archiveId;
cmdbuf[3] = archivePath.type;
cmdbuf[4] = archivePath.size;
cmdbuf[5] = filePath.type;
cmdbuf[6] = filePath.size;
cmdbuf[7] = openFlags;
cmdbuf[8] = attributes;
cmdbuf[9] = IPC_Desc_StaticBuffer(archivePath.size, 2);
cmdbuf[10] = (u32)archivePath.data;
cmdbuf[11] = IPC_Desc_StaticBuffer(filePath.size, 0);
cmdbuf[12] = (u32)filePath.data;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
if(out) *out = cmdbuf[3];
return cmdbuf[1];
}

9
injector/source/fsldr.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <3ds/types.h>
Result fsldrInit(void);
void fsldrExit(void);
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version);
Result FSLDR_SetPriority(u32 priority);
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes);

116
injector/source/fsreg.c Normal file
View File

@@ -0,0 +1,116 @@
#include <3ds.h>
#include <string.h>
#include "fsreg.h"
#include "srvsys.h"
static Handle fsregHandle;
static int fsregRefCount;
Result fsregInit(void)
{
Result ret = 0;
if (AtomicPostIncrement(&fsregRefCount)) return 0;
ret = srvSysGetServiceHandle(&fsregHandle, "fs:REG");
if (R_FAILED(ret)) AtomicDecrement(&fsregRefCount);
return ret;
}
void fsregExit(void)
{
if (AtomicDecrement(&fsregRefCount)) return;
svcCloseHandle(fsregHandle);
}
Result FSREG_CheckHostLoadId(u64 prog_handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x406,2,0); // 0x4060080
cmdbuf[1] = (u32) (prog_handle);
cmdbuf[2] = (u32) (prog_handle >> 32);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
return cmdbuf[1];
}
Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x404,4,0); // 0x4040100
memcpy(&cmdbuf[1], &title->programId, sizeof(u64));
*(u8 *)&cmdbuf[3] = title->mediaType;
memcpy(((u8 *)&cmdbuf[3])+1, &title->padding, 7);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
*prog_handle = *(u64 *)&cmdbuf[2];
return cmdbuf[1];
}
Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x403,3,0); // 0x40300C0
cmdbuf[1] = entry_count;
*(u64 *)&cmdbuf[2] = prog_handle;
cmdbuf[64] = ((entry_count << 10) << 14) | 2;
cmdbuf[65] = (u32) exheader;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
return cmdbuf[1];
}
Result FSREG_UnloadProgram(u64 prog_handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x405,2,0); // 0x4050080
cmdbuf[1] = (u32) (prog_handle);
cmdbuf[2] = (u32) (prog_handle >> 32);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
return cmdbuf[1];
}
Result FSREG_Unregister(u32 pid)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x402,1,0); // 0x4020040
cmdbuf[1] = pid;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
return cmdbuf[1];
}
Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x401,0xf,0); // 0x40103C0
cmdbuf[1] = pid;
*(u64 *)&cmdbuf[2] = prog_handle;
memcpy(&cmdbuf[4], &info->programId, sizeof(u64));
*(u8 *)&cmdbuf[6] = info->mediaType;
memcpy(((u8 *)&cmdbuf[6])+1, &info->padding, 7);
memcpy((u8 *)&cmdbuf[8], storageinfo, 32);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret;
return cmdbuf[1];
}

13
injector/source/fsreg.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <3ds/types.h>
#include "exheader.h"
Result fsregInit(void);
void fsregExit(void);
Result FSREG_CheckHostLoadId(u64 prog_handle);
Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title);
Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle);
Result FSREG_UnloadProgram(u64 prog_handle);
Result FSREG_Unregister(u32 pid);
Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo);

66
injector/source/ifile.c Normal file
View File

@@ -0,0 +1,66 @@
#include <3ds.h>
#include "ifile.h"
#include "fsldr.h"
Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags)
{
Result res;
res = FSLDR_OpenFileDirectly(&file->handle, archiveId, archivePath, filePath, flags, 0);
file->pos = 0;
file->size = 0;
return res;
}
Result IFile_Close(IFile *file)
{
return FSFILE_Close(file->handle);
}
Result IFile_GetSize(IFile *file, u64 *size)
{
Result res;
res = FSFILE_GetSize(file->handle, size);
file->size = *size;
return res;
}
Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len)
{
u32 read;
u32 left;
char *buf;
u64 cur;
Result res;
if (len == 0)
{
*total = 0;
return 0;
}
buf = (char *)buffer;
cur = 0;
left = len;
while (1)
{
res = FSFILE_Read(file->handle, &read, file->pos, buf, left);
if (R_FAILED(res))
{
break;
}
cur += read;
file->pos += read;
if (read == left)
{
break;
}
buf += read;
left -= read;
}
*total = cur;
return res;
}

15
injector/source/ifile.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <3ds/types.h>
typedef struct
{
Handle handle;
u64 pos;
u64 size;
} IFile;
Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags);
Result IFile_Close(IFile *file);
Result IFile_GetSize(IFile *file, u64 *size);
Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);

591
injector/source/loader.c Normal file
View File

@@ -0,0 +1,591 @@
#include <3ds.h>
#include "memory.h"
#include "patcher.h"
#include "exheader.h"
#include "ifile.h"
#include "fsldr.h"
#include "fsreg.h"
#include "pxipm.h"
#include "srvsys.h"
#define MAX_SESSIONS 1
const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00};
typedef struct
{
u32 text_addr;
u32 text_size;
u32 ro_addr;
u32 ro_size;
u32 data_addr;
u32 data_size;
u32 total_size;
} prog_addrs_t;
static Handle g_handles[MAX_SESSIONS+2];
static int g_active_handles;
static u64 g_cached_prog_handle;
static exheader_header g_exheader;
static char g_ret_buf[1024];
static int lzss_decompress(u8 *end)
{
unsigned int v1; // r1@2
u8 *v2; // r2@2
u8 *v3; // r3@2
u8 *v4; // r1@2
char v5; // r5@4
char v6; // t1@4
signed int v7; // r6@4
int v9; // t1@7
u8 *v11; // r3@8
int v12; // r12@8
int v13; // t1@8
int v14; // t1@8
unsigned int v15; // r7@8
int v16; // r12@8
int ret;
ret = 0;
if ( end )
{
v1 = *((u32 *)end - 2);
v2 = &end[*((u32 *)end - 1)];
v3 = &end[-(v1 >> 24)];
v4 = &end[-(v1 & 0xFFFFFF)];
while ( v3 > v4 )
{
v6 = *(v3-- - 1);
v5 = v6;
v7 = 8;
while ( 1 )
{
if ( (v7-- < 1) )
break;
if ( v5 & 0x80 )
{
v13 = *(v3 - 1);
v11 = v3 - 1;
v12 = v13;
v14 = *(v11 - 1);
v3 = v11 - 1;
v15 = ((v14 | (v12 << 8)) & 0xFFFF0FFF) + 2;
v16 = v12 + 32;
do
{
ret = v2[v15];
*(v2-- - 1) = ret;
v16 -= 16;
}
while ( !(v16 < 0) );
}
else
{
v9 = *(v3-- - 1);
ret = v9;
*(v2-- - 1) = v9;
}
v5 *= 2;
if ( v3 <= v4 )
return ret;
}
}
}
return ret;
}
static Result allocate_shared_mem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags)
{
u32 dummy;
memcpy(shared, vaddr, sizeof(prog_addrs_t));
shared->text_addr = 0x10000000;
shared->ro_addr = shared->text_addr + (shared->text_size << 12);
shared->data_addr = shared->ro_addr + (shared->ro_size << 12);
return svcControlMemory(&dummy, shared->text_addr, 0, shared->total_size << 12, (flags & 0xF00) | MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
}
static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int is_compressed)
{
IFile file;
FS_Path archivePath;
FS_Path filePath;
Result res;
u64 size;
u64 total;
archivePath.type = PATH_BINARY;
archivePath.data = &prog_handle;
archivePath.size = 8;
filePath.type = PATH_BINARY;
filePath.data = CODE_PATH;
filePath.size = sizeof(CODE_PATH);
if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
{
svcBreak(USERBREAK_ASSERT);
}
// get file size
if (R_FAILED(IFile_GetSize(&file, &size)))
{
IFile_Close(&file);
svcBreak(USERBREAK_ASSERT);
}
// check size
if (size > (u64)shared->total_size << 12)
{
IFile_Close(&file);
return 0xC900464F;
}
// read code
res = IFile_Read(&file, &total, (void *)shared->text_addr, size);
IFile_Close(&file); // done reading
if (R_FAILED(res))
{
svcBreak(USERBREAK_ASSERT);
}
// decompress
if (is_compressed)
{
lzss_decompress((u8 *)shared->text_addr + size);
}
// patch
patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
return 0;
}
static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle)
{
Result res;
if (prog_handle >> 32 == 0xFFFF0000)
{
return FSREG_GetProgramInfo(exheader, 1, prog_handle);
}
else
{
res = FSREG_CheckHostLoadId(prog_handle);
//if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32))
//so use PXIPM if FSREG fails OR returns "info", is the second condition a bug?
if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS))
{
return PXIPM_GetProgramInfo(exheader, prog_handle);
}
else
{
return FSREG_GetProgramInfo(exheader, 1, prog_handle);
}
}
}
static Result loader_LoadProcess(Handle *process, u64 prog_handle)
{
Result res;
int count;
u32 flags;
u32 desc;
u32 dummy;
prog_addrs_t shared_addr;
prog_addrs_t vaddr;
Handle codeset;
CodeSetInfo codesetinfo;
u32 data_mem_size;
u64 progid;
// make sure the cached info corrosponds to the current prog_handle
if (g_cached_prog_handle != prog_handle)
{
res = loader_GetProgramInfo(&g_exheader, prog_handle);
g_cached_prog_handle = prog_handle;
if (res < 0)
{
g_cached_prog_handle = 0;
return res;
}
}
// get kernel flags
flags = 0;
for (count = 0; count < 28; count++)
{
desc = g_exheader.arm11kernelcaps.descriptors[count];
if (0x1FE == desc >> 23)
{
flags = desc & 0xF00;
}
}
if (flags == 0)
{
return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2);
}
// allocate process memory
vaddr.text_addr = g_exheader.codesetinfo.text.address;
vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> 12;
vaddr.ro_addr = g_exheader.codesetinfo.ro.address;
vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + 4095) >> 12;
vaddr.data_addr = g_exheader.codesetinfo.data.address;
vaddr.data_size = (g_exheader.codesetinfo.data.codesize + 4095) >> 12;
data_mem_size = (g_exheader.codesetinfo.data.codesize + g_exheader.codesetinfo.bsssize + 4095) >> 12;
vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size;
if ((res = allocate_shared_mem(&shared_addr, &vaddr, flags)) < 0)
{
return res;
}
// load code
progid = g_exheader.arm11systemlocalcaps.programid;
if ((res = load_code(progid, &shared_addr, prog_handle, g_exheader.codesetinfo.flags.flag & 1)) >= 0)
{
memcpy(&codesetinfo.name, g_exheader.codesetinfo.name, 8);
codesetinfo.program_id = progid;
codesetinfo.text_addr = vaddr.text_addr;
codesetinfo.text_size = vaddr.text_size;
codesetinfo.text_size_total = vaddr.text_size;
codesetinfo.ro_addr = vaddr.ro_addr;
codesetinfo.ro_size = vaddr.ro_size;
codesetinfo.ro_size_total = vaddr.ro_size;
codesetinfo.rw_addr = vaddr.data_addr;
codesetinfo.rw_size = vaddr.data_size;
codesetinfo.rw_size_total = data_mem_size;
res = svcCreateCodeSet(&codeset, &codesetinfo, (void *)shared_addr.text_addr, (void *)shared_addr.ro_addr, (void *)shared_addr.data_addr);
if (res >= 0)
{
res = svcCreateProcess(process, codeset, g_exheader.arm11kernelcaps.descriptors, count);
svcCloseHandle(codeset);
if (res >= 0)
{
return 0;
}
}
}
svcControlMemory(&dummy, shared_addr.text_addr, 0, shared_addr.total_size << 12, MEMOP_FREE, 0);
return res;
}
static Result loader_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update)
{
Result res;
u64 prog_id;
prog_id = title->programId;
if (prog_id >> 32 != 0xFFFF0000)
{
res = FSREG_CheckHostLoadId(prog_id);
//if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32))
if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS))
{
res = PXIPM_RegisterProgram(prog_handle, title, update);
if (res < 0)
{
return res;
}
if (*prog_handle >> 32 != 0xFFFF0000)
{
res = FSREG_CheckHostLoadId(*prog_handle);
//if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32))
if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS))
{
return 0;
}
}
svcBreak(USERBREAK_ASSERT);
}
}
if ((title->mediaType != update->mediaType) || (prog_id != update->programId))
{
svcBreak(USERBREAK_ASSERT);
}
res = FSREG_LoadProgram(prog_handle, title);
if (R_SUCCEEDED(res))
{
if (*prog_handle >> 32 == 0xFFFF0000)
{
return 0;
}
res = FSREG_CheckHostLoadId(*prog_handle);
//if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32))
if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS))
{
svcBreak(USERBREAK_ASSERT);
}
}
return res;
}
static Result loader_UnregisterProgram(u64 prog_handle)
{
Result res;
if (prog_handle >> 32 == 0xFFFF0000)
{
return FSREG_UnloadProgram(prog_handle);
}
else
{
res = FSREG_CheckHostLoadId(prog_handle);
//if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32))
if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS))
{
return PXIPM_UnregisterProgram(prog_handle);
}
else
{
return FSREG_UnloadProgram(prog_handle);
}
}
}
static void handle_commands(void)
{
FS_ProgramInfo title;
FS_ProgramInfo update;
u32* cmdbuf;
u16 cmdid;
int res;
Handle handle;
u64 prog_handle;
cmdbuf = getThreadCommandBuffer();
cmdid = cmdbuf[0] >> 16;
res = 0;
switch (cmdid)
{
case 1: // LoadProcess
{
res = loader_LoadProcess(&handle, *(u64 *)&cmdbuf[1]);
cmdbuf[0] = 0x10042;
cmdbuf[1] = res;
cmdbuf[2] = 16;
cmdbuf[3] = handle;
break;
}
case 2: // RegisterProgram
{
memcpy(&title, &cmdbuf[1], sizeof(FS_ProgramInfo));
memcpy(&update, &cmdbuf[5], sizeof(FS_ProgramInfo));
res = loader_RegisterProgram(&prog_handle, &title, &update);
cmdbuf[0] = 0x200C0;
cmdbuf[1] = res;
*(u64 *)&cmdbuf[2] = prog_handle;
break;
}
case 3: // UnregisterProgram
{
if (g_cached_prog_handle == prog_handle)
{
g_cached_prog_handle = 0;
}
cmdbuf[0] = 0x30040;
cmdbuf[1] = loader_UnregisterProgram(*(u64 *)&cmdbuf[1]);
break;
}
case 4: // GetProgramInfo
{
prog_handle = *(u64 *)&cmdbuf[1];
if (prog_handle != g_cached_prog_handle)
{
res = loader_GetProgramInfo(&g_exheader, prog_handle);
if (res >= 0)
{
g_cached_prog_handle = prog_handle;
}
else
{
g_cached_prog_handle = 0;
}
}
memcpy(&g_ret_buf, &g_exheader, 1024);
cmdbuf[0] = 0x40042;
cmdbuf[1] = res;
cmdbuf[2] = 0x1000002;
cmdbuf[3] = (u32) &g_ret_buf;
break;
}
default: // error
{
cmdbuf[0] = 0x40;
cmdbuf[1] = 0xD900182F;
break;
}
}
}
static Result should_terminate(int *term_request)
{
u32 notid;
Result ret;
ret = srvSysReceiveNotification(&notid);
if (R_FAILED(ret))
{
return ret;
}
if (notid == 0x100) // term request
{
*term_request = 1;
}
return 0;
}
// this is called before main
void __appInit()
{
srvSysInit();
fsregInit();
fsldrInit();
pxipmInit();
}
// this is called after main exits
void __appExit()
{
pxipmExit();
fsldrExit();
fsregExit();
srvSysExit();
}
// stubs for non-needed pre-main functions
void __sync_init();
void __sync_fini();
void __system_initSyscalls();
void __ctru_exit()
{
__appExit();
__sync_fini();
svcExitProcess();
}
void initSystem()
{
__sync_init();
__system_initSyscalls();
__appInit();
}
int main()
{
Result ret;
Handle handle;
Handle reply_target;
Handle *srv_handle;
Handle *notification_handle;
s32 index;
int i;
int term_request;
u32* cmdbuf;
ret = 0;
srv_handle = &g_handles[1];
notification_handle = &g_handles[0];
if (R_FAILED(srvSysRegisterService(srv_handle, "Loader", MAX_SESSIONS)))
{
svcBreak(USERBREAK_ASSERT);
}
if (R_FAILED(srvSysEnableNotification(notification_handle)))
{
svcBreak(USERBREAK_ASSERT);
}
g_active_handles = 2;
g_cached_prog_handle = 0;
index = 1;
reply_target = 0;
term_request = 0;
do
{
if (reply_target == 0)
{
cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0xFFFF0000;
}
ret = svcReplyAndReceive(&index, g_handles, g_active_handles, reply_target);
if (R_FAILED(ret))
{
// check if any handle has been closed
if (ret == (int)0xC920181A)
{
if (index == -1)
{
for (i = 2; i < MAX_SESSIONS+2; i++)
{
if (g_handles[i] == reply_target)
{
index = i;
break;
}
}
}
svcCloseHandle(g_handles[index]);
g_handles[index] = g_handles[g_active_handles-1];
g_active_handles--;
reply_target = 0;
}
else
{
svcBreak(USERBREAK_ASSERT);
}
}
else
{
// process responses
reply_target = 0;
switch (index)
{
case 0: // notification
{
if (R_FAILED(should_terminate(&term_request)))
{
svcBreak(USERBREAK_ASSERT);
}
break;
}
case 1: // new session
{
if (R_FAILED(svcAcceptSession(&handle, *srv_handle)))
{
svcBreak(USERBREAK_ASSERT);
}
if (g_active_handles < MAX_SESSIONS+2)
{
g_handles[g_active_handles] = handle;
g_active_handles++;
}
else
{
svcCloseHandle(handle);
}
break;
}
default: // session
{
handle_commands();
reply_target = g_handles[index];
break;
}
}
}
} while (!term_request || g_active_handles != 2);
srvSysUnregisterService("Loader");
svcCloseHandle(*srv_handle);
svcCloseHandle(*notification_handle);
return 0;
}

10
injector/source/memory.c Normal file
View File

@@ -0,0 +1,10 @@
#include "memory.h"
void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++)
destc[i] = srcc[i];
}

5
injector/source/memory.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <3ds/types.h>
void memcpy(void *dest, const void *src, u32 size);

577
injector/source/patcher.c Normal file
View File

@@ -0,0 +1,577 @@
#include <3ds.h>
#include "memory.h"
#include "patcher.h"
#include "ifile.h"
static CFWInfo info = {0};
static int memcmp(const void *buf1, const void *buf2, u32 size)
{
const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i];
if(cmp) return cmp;
}
return 0;
}
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern;
//Preprocessing
u32 table[256];
for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1;
for(u32 i = 0; i < patternSize; ++i)
table[patternc[i]] = patternSize - i;
//Searching
u32 j = 0;
while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j;
j += table[startPos[j + patternSize]];
}
return NULL;
}
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
{
u32 i;
for(i = 0; i < count; i++)
{
u8 *found = memsearch(start, pattern, size, patSize);
if(found == NULL) break;
memcpy(found + offset, replace, repSize);
u32 at = (u32)(found - start);
if(at + patSize > size) break;
size -= at + patSize;
start = found + patSize;
}
return i;
}
static inline size_t strnlen(const char *string, size_t maxlen)
{
size_t size;
for(size = 0; *string && size < maxlen; string++, size++);
return size;
}
static int fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
{
FS_Path filePath = {PATH_ASCII, strnlen(path, PATH_MAX) + 1, path},
archivePath = {PATH_EMPTY, 1, (u8 *)""};
return IFile_Open(file, archiveId, archivePath, filePath, flags);
}
int __attribute__((naked)) svcGetCFWInfo(CFWInfo __attribute__((unused)) *out)
{
__asm__ volatile("svc 0x2E; bx lr");
}
static void loadCFWInfo(void)
{
static bool infoLoaded = false;
if(!infoLoaded)
{
svcGetCFWInfo(&info);
IFile file;
if(BOOTCONFIG(5, 1) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted
{
IFile_Close(&file);
}
infoLoaded = true;
}
}
static bool secureInfoExists(void)
{
static bool exists = false;
if(!exists)
{
IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
{
exists = true;
IFile_Close(&file);
}
}
return exists;
}
static void progIdToStr(char *strEnd, u64 progId)
{
while(progId)
{
static const char hexDigits[] = "0123456789ABCDEF";
*strEnd-- = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
}
static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
{
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
If it exists it should be a decompressed binary code file */
char path[] = "/luma/code_sections/0000000000000000.bin";
progIdToStr(path + 35, progId);
IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret))
{
u64 fileSize, total;
ret = IFile_GetSize(&file, &fileSize);
if(R_SUCCEEDED(ret) && fileSize <= size)
{
ret = IFile_Read(&file, &total, code, fileSize);
IFile_Close(&file);
}
}
}
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
{
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
If it exists it should contain, for example, "EUR IT" */
char path[] = "/luma/locales/0000000000000000.txt";
progIdToStr(path + 29, progId);
IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret))
{
char buf[6];
u64 total;
ret = IFile_Read(&file, &total, buf, 6);
IFile_Close(&file);
if(!R_SUCCEEDED(ret) || total < 6) return -1;
for(u32 i = 0; i < 7; ++i)
{
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
if(memcmp(buf, regions[i], 3) == 0)
{
*regionId = (u8)i;
break;
}
}
for(u32 i = 0; i < 12; ++i)
{
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
if(memcmp(buf + 4, languages[i], 2) == 0)
{
*languageId = (u8)i;
break;
}
}
}
return ret;
}
static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
{
/* HANS:
Look for error code which is known to be stored near cfg:u handle
this way we can find the right candidate
(handle should also be stored right after end of candidate function) */
u32 n = 0,
possible[24];
for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
{
if(*(u32 *)pos == 0xD8A103F9)
{
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
if(*l <= 0x10000000) possible[n++] = *l;
}
}
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
{
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
{
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
for(u32 i = 0; i < n; i++)
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
CFGU_GetConfigInfoBlk2_endPos += 4;
}
}
return NULL;
}
static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
{
u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind)
for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
CFGU_GetConfigInfoBlk2_startPos -= 2);
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
{
if(*(u32 *)languageBlkIdPos == 0xA0002)
{
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
{
if(instr[3] == 0xEB) //We're looking for BL
{
u8 *calledFunction = instr;
u32 i = 0;
bool found;
do
{
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
calledFunction += offset;
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
i++;
}
while(i < 2 && !found && calledFunction[3] == 0xEA);
if(found)
{
*((u32 *)instr - 1) = 0xE3A00000 | languageId; // mov r0, sp => mov r0, =languageId
*(u32 *)instr = 0xE5CD0000; // bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
*((u32 *)instr + 1) = 0xE3B00000; // (1 or 2 instructions) => movs r0, 0 (result code)
//We're done
return;
}
}
}
}
}
}
static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset)
{
for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
{
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
u32 *cmp = (u32 *)cmdPos;
if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
*(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset)
{
*((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId
*((u32 *)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8]
*((u32 *)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result code) ('s' not needed but nvm)
*((u32 *)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4]
//The remaining, not patched, function code will do the rest for us
break;
}
}
}
void patchCode(u64 progId, u8 *code, u32 size)
{
loadCFWInfo();
switch(progId)
{
case 0x0004003000008F02LL: // USA Menu
case 0x0004003000008202LL: // EUR Menu
case 0x0004003000009802LL: // JPN Menu
case 0x000400300000A102LL: // CHN Menu
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
};
static const u8 regionFreePatch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
};
//Patch SMDH region checks
patchMemory(code, size,
regionFreePattern,
sizeof(regionFreePattern), -16,
regionFreePatch,
sizeof(regionFreePatch), 1
);
break;
}
case 0x0004013000002C02LL: // NIM
{
static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99
};
static const u8 blockAutoUpdatesPatch[] = {
0xE3, 0xA0
};
//Block silent auto-updates
patchMemory(code, size,
blockAutoUpdatesPattern,
sizeof(blockAutoUpdatesPattern), 0,
blockAutoUpdatesPatch,
sizeof(blockAutoUpdatesPatch), 1
);
//Apply only if the updated NAND hasn't been booted
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(2, 1) && CONFIG(1)))
{
static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0
};
static const u8 skipEshopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
};
//Skip update checks to access the EShop
patchMemory(code, size,
skipEshopUpdateCheckPattern,
sizeof(skipEshopUpdateCheckPattern), 0,
skipEshopUpdateCheckPatch,
sizeof(skipEshopUpdateCheckPatch), 1
);
}
break;
}
case 0x0004013000003202LL: // FRIENDS
{
static const u8 fpdVerPattern[] = {
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
};
static const u8 mostRecentFpdVer = 0x06;
u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
//Allow online access to work with old friends modules, without breaking newer firmwares
if(fpdVer != NULL && fpdVer[9] < mostRecentFpdVer) fpdVer[9] = mostRecentFpdVer;
break;
}
case 0x0004001000021000LL: // USA MSET
case 0x0004001000020000LL: // JPN MSET
case 0x0004001000022000LL: // EUR MSET
case 0x0004001000026000LL: // CHN MSET
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
if(CONFIG(4))
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
//Patch Ver. string
patchMemory(code, size,
verPattern,
sizeof(verPattern) - sizeof(u16), 0,
!currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
sizeof(verPattern) - sizeof(u16), 1
);
}
break;
}
case 0x0004013000008002LL: // NS
{
static const u8 stopCartUpdatesPattern[] = {
0x0C, 0x18, 0xE1, 0xD8
};
static const u8 stopCartUpdatesPatch[] = {
0x0B, 0x18, 0x21, 0xC8
};
//Disable updates from foreign carts (makes carts region-free)
patchMemory(code, size,
stopCartUpdatesPattern,
sizeof(stopCartUpdatesPattern), 0,
stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2
);
u32 cpuSetting = MULTICONFIG(1);
if(cpuSetting)
{
static const u8 cfgN3dsCpuPattern[] = {
0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00
};
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
//Patch N3DS CPU Clock and L2 cache setting
if(cfgN3dsCpuLoc != NULL)
{
*(cfgN3dsCpuLoc + 1) = 0xE1A00000;
*(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting;
}
}
break;
}
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC
};
static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26
};
//Disable SecureInfo signature check
patchMemory(code, size,
secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0,
secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1
);
if(secureInfoExists())
{
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
//Use SecureInfo_C
patchMemory(code, size,
secureinfoFilenamePattern,
sizeof(secureinfoFilenamePattern) - sizeof(u16),
sizeof(secureinfoFilenamePattern) - sizeof(u16),
secureinfoFilenamePatch,
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
);
}
break;
}
case 0x0004013000003702LL: // RO
{
static const u8 sigCheckPattern[] = {
0x30, 0x40, 0x2D, 0xE9, 0x02
};
static const u8 sha256ChecksPattern1[] = {
0x30, 0x40, 0x2D, 0xE9, 0x24
};
static const u8 sha256ChecksPattern2[] = {
0xF8, 0x4F, 0x2D, 0xE9, 0x01
};
static const u8 stub[] = {
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 // mov r0, #0; bx lr
};
//Disable CRR0 signature (RSA2048 with SHA256) check
patchMemory(code, size,
sigCheckPattern,
sizeof(sigCheckPattern), 0,
stub,
sizeof(stub), 1
);
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
patchMemory(code, size,
sha256ChecksPattern1,
sizeof(sha256ChecksPattern1), 0,
stub,
sizeof(stub), 1
);
patchMemory(code, size,
sha256ChecksPattern2,
sizeof(sha256ChecksPattern2), 0,
stub,
sizeof(stub), 1
);
break;
}
default:
if(CONFIG(3))
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
if(tidHigh == 0x0004000)
{
//External .code section loading
loadTitleCodeSection(progId, code, size);
//Language emulation
u8 regionId = 0xFF,
languageId = 0xFF;
if(R_SUCCEEDED(loadTitleLocaleConfig(progId, &regionId, &languageId)))
{
u32 CFGUHandleOffset;
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
{
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
}
}
}
}
break;
}
}

25
injector/source/patcher.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include <3ds/types.h>
#define PATH_MAX 255
#define CONFIG(a) (((info.config >> (a + 16)) & 1) != 0)
#define MULTICONFIG(a) ((info.config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
typedef struct __attribute__((packed))
{
char magic[4];
u8 versionMajor;
u8 versionMinor;
u8 versionBuild;
u8 flags; /* bit 0: dev branch; bit 1: is release */
u32 commitHash;
u32 config;
} CFWInfo;
void patchCode(u64 progId, u8 *code, u32 size);

74
injector/source/pxipm.c Normal file
View File

@@ -0,0 +1,74 @@
#include <3ds.h>
#include <string.h>
#include "pxipm.h"
#include "srvsys.h"
static Handle pxipmHandle;
static int pxipmRefCount;
Result pxipmInit(void)
{
Result ret = 0;
if (AtomicPostIncrement(&pxipmRefCount)) return 0;
ret = srvSysGetServiceHandle(&pxipmHandle, "PxiPM");
if (R_FAILED(ret)) AtomicDecrement(&pxipmRefCount);
return ret;
}
void pxipmExit(void)
{
if (AtomicDecrement(&pxipmRefCount)) return;
svcCloseHandle(pxipmHandle);
}
Result PXIPM_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x2,8,0); // 0x20200
memcpy(&cmdbuf[1], &title->programId, sizeof(u64));
*(u8 *)&cmdbuf[3] = title->mediaType;
memcpy(((u8 *)&cmdbuf[3])+1, &title->padding, 7);
memcpy(&cmdbuf[5], &update->programId, sizeof(u64));
*(u8 *)&cmdbuf[7] = update->mediaType;
memcpy(((u8 *)&cmdbuf[7])+1, &update->padding, 7);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret;
*prog_handle = *(u64*)&cmdbuf[2];
return cmdbuf[1];
}
Result PXIPM_GetProgramInfo(exheader_header *exheader, u64 prog_handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x1,2,2); // 0x10082
cmdbuf[1] = (u32) (prog_handle);
cmdbuf[2] = (u32) (prog_handle >> 32);
cmdbuf[3] = (0x400 << 8) | 0x4;
cmdbuf[4] = (u32) exheader;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret;
return cmdbuf[1];
}
Result PXIPM_UnregisterProgram(u64 prog_handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x3,2,0); // 0x30080
cmdbuf[1] = (u32) (prog_handle);
cmdbuf[2] = (u32) (prog_handle >> 32);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret;
return cmdbuf[1];
}

10
injector/source/pxipm.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <3ds/types.h>
#include "exheader.h"
Result pxipmInit(void);
void pxipmExit(void);
Result PXIPM_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update);
Result PXIPM_GetProgramInfo(exheader_header *exheader, u64 prog_handle);
Result PXIPM_UnregisterProgram(u64 prog_handle);

154
injector/source/srvsys.c Normal file
View File

@@ -0,0 +1,154 @@
#include <3ds.h>
#include <string.h>
#include "srvsys.h"
static Handle srvHandle;
static int srvRefCount;
static RecursiveLock initLock;
static int initLockinit = 0;
Result srvSysInit()
{
Result rc = 0;
if (!initLockinit)
{
RecursiveLock_Init(&initLock);
}
RecursiveLock_Lock(&initLock);
if (srvRefCount > 0)
{
RecursiveLock_Unlock(&initLock);
return MAKERESULT(RL_INFO, RS_NOP, 25, RD_ALREADY_INITIALIZED);
}
while (1)
{
rc = svcConnectToPort(&srvHandle, "srv:");
if (R_LEVEL(rc) != RL_PERMANENT ||
R_SUMMARY(rc) != RS_NOTFOUND ||
R_DESCRIPTION(rc) != RD_NOT_FOUND
) break;
svcSleepThread(500000);
}
if (R_SUCCEEDED(rc))
{
rc = srvSysRegisterClient();
srvRefCount++;
}
RecursiveLock_Unlock(&initLock);
return rc;
}
Result srvSysRegisterClient(void)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x1,0,2); // 0x10002
cmdbuf[1] = IPC_Desc_CurProcessHandle();
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
return cmdbuf[1];
}
Result srvSysExit()
{
Result rc;
RecursiveLock_Lock(&initLock);
if (srvRefCount > 1)
{
srvRefCount--;
RecursiveLock_Unlock(&initLock);
return MAKERESULT(RL_INFO, RS_NOP, 25, RD_BUSY);
}
if (srvHandle != 0) svcCloseHandle(srvHandle);
else svcBreak(USERBREAK_ASSERT);
rc = (Result)srvHandle; // yeah, I think this is a benign bug
srvHandle = 0;
srvRefCount--;
RecursiveLock_Unlock(&initLock);
return rc;
}
Result srvSysGetServiceHandle(Handle* out, const char* name)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
cmdbuf[4] = 0x0;
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
if(out) *out = cmdbuf[3];
return cmdbuf[1];
}
Result srvSysEnableNotification(Handle* semaphoreOut)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x2,0,0);
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
if(semaphoreOut) *semaphoreOut = cmdbuf[3];
return cmdbuf[1];
}
Result srvSysReceiveNotification(u32* notificationIdOut)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xB,0,0); // 0xB0000
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
if(notificationIdOut) *notificationIdOut = cmdbuf[2];
return cmdbuf[1];
}
Result srvSysRegisterService(Handle* out, const char* name, int maxSessions)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x3,4,0); // 0x30100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
cmdbuf[4] = maxSessions;
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
if(out) *out = cmdbuf[3];
return cmdbuf[1];
}
Result srvSysUnregisterService(const char* name)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x4,3,0); // 0x400C0
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strlen(name);
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
return cmdbuf[1];
}

47
injector/source/srvsys.h Normal file
View File

@@ -0,0 +1,47 @@
/**
* @file srv.h
* @brief Service API.
*/
#pragma once
/// Initializes the service API.
Result srvSysInit(void);
/// Exits the service API.
Result srvSysExit(void);
/**
* @brief Retrieves a service handle, retrieving from the environment handle list if possible.
* @param out Pointer to write the handle to.
* @param name Name of the service.
*/
Result srvSysGetServiceHandle(Handle* out, const char* name);
/// Registers the current process as a client to the service API.
Result srvSysRegisterClient(void);
/**
* @brief Enables service notificatios, returning a notification semaphore.
* @param semaphoreOut Pointer to output the notification semaphore to.
*/
Result srvSysEnableNotification(Handle* semaphoreOut);
/**
* @brief Receives a notification.
* @param notificationIdOut Pointer to output the ID of the received notification to.
*/
Result srvSysReceiveNotification(u32* notificationIdOut);
/**
* @brief Registers the current process as a service.
* @param out Pointer to write the service handle to.
* @param name Name of the service.
* @param maxSessions Maximum number of sessions the service can handle.
*/
Result srvSysRegisterService(Handle* out, const char* name, int maxSessions);
/**
* @brief Unregisters the current process as a service.
* @param name Name of the service.
*/
Result srvSysUnregisterService(const char* name);

49
loader/Makefile Normal file
View File

@@ -0,0 +1,49 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: ../$(dir_build)/$(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/memory.o: CFLAGS += -O3
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

11
loader/linker.ld Normal file
View File

@@ -0,0 +1,11 @@
ENTRY(_start)
SECTIONS
{
. = 0x24FFFF00;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

27
loader/source/cache.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
void flushCaches(void);

52
loader/source/cache.s Normal file
View File

@@ -0,0 +1,52 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
.arm
.global flushCaches
.type flushCaches STT_FUNC
flushCaches:
@ Clean and flush data cache
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
@ Implemented in bootROM at address 0xffff0830
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
@ Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
bx lr

37
loader/source/main.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "memory.h"
#include "cache.h"
extern u32 payloadSize; //defined in start.s
void main(void)
{
void *payloadAddress = (void *)0x23F00000;
memcpy(payloadAddress, (void*)0x24F00000, payloadSize);
flushCaches();
((void (*)())payloadAddress)();
}

37
loader/source/memory.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#include "memory.h"
void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++)
destc[i] = srcc[i];
}

32
loader/source/memory.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#pragma once
#include "types.h"
void memcpy(void *dest, const void *src, u32 size);

29
loader/source/start.s Normal file
View File

@@ -0,0 +1,29 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
.section .text.start
.align 4
.global _start
_start:
b main
.global payloadSize
payloadSize:
.word 0

35
loader/source/types.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include <stdint.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;

View File

@@ -1,9 +1,6 @@
.nds .arm.little
sdmmc equ 0x434D4453 ;dummy .create "build/emunand.bin", 0
.create "emunand.bin", 0x0801A5C0
.org 0x0801A5C0
.arm .arm
nand_sd: nand_sd:
; Original code that still needs to be executed. ; Original code that still needs to be executed.
@@ -15,7 +12,7 @@ nand_sd:
; If we're already trying to access the SD, return. ; If we're already trying to access the SD, return.
ldr r2, [r0, #4] ldr r2, [r0, #4]
ldr r1, =sdmmc ldr r1, [sdmmc]
cmp r2, r1 cmp r2, r1
beq nand_sd_ret beq nand_sd_ret
@@ -23,12 +20,10 @@ nand_sd:
ldr r2, [r0, #8] ; Get sector to read ldr r2, [r0, #8] ; Get sector to read
cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0) cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0)
ldr r3, =nand_offset ldr r3, [nand_offset]
ldr r3, [r3]
add r2, r3 ; Add the offset to the NAND in the SD. add r2, r3 ; Add the offset to the NAND in the SD.
ldreq r3, =ncsd_header_offset ldreq r3, [ncsd_header_offset]
ldreq r3, [r3]
addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector. addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector.
str r2, [r0, #8] ; Store sector to read str r2, [r0, #8] ; Store sector to read
@@ -45,6 +40,7 @@ nand_sd:
add r0, #4 add r0, #4
bx r0 bx r0
.pool .pool
sdmmc: .ascii "SDMC"
nand_offset: .ascii "NAND" ; for rednand this should be 1 nand_offset: .ascii "NAND" ; for rednand this should be 1
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED) ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
.close .close

125
patches/reboot.s Normal file
View File

@@ -0,0 +1,125 @@
.arm.little
payload_addr equ 0x23F00000 ; Brahma payload address.
payload_maxsize equ 0x10000 ; Maximum size for the payload (maximum that CakeBrah supports).
.create "build/reboot.bin", 0
.arm
; Interesting registers and locations to keep in mind, set before this code is ran:
; - sp + 0x3A8 - 0x70: FIRM path in exefs.
; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
pxi_wait_recv:
ldr r2, =0x44846
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0, #4]
lsls r1, #0x17
bmi readPxiLoop1
ldr r0, [r0, #0xC]
cmp r0, r2
bne pxi_wait_recv
mov r4, #0
adr r1, bin_fname
b open_payload
fallback:
mov r4, #1
adr r1, dat_fname
open_payload:
; Open file
add r0, r7, #8
mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6
cmp r0, #0
bne fallback ; If the .bin is not found, try the .dat.
read_payload:
; Read file
mov r0, r7
adr r1, bytes_read
ldr r2, =payload_addr
cmp r4, #0
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28]
blx r6
cmp r4, #0
movne r4, #0
bne read_payload ; Go read the real payload.
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
add r0, sp, #0x3A8 - 0x70
add r0, 0x1A
add r1, r0, #0x10
ldr r2, =payload_addr + 4
copy_TID_low:
ldrh r3, [r0], #2
strh r3, [r2], #2
cmp r0, r1
blo copy_TID_low
; Set kernel state
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
swi 0x7C
goto_reboot:
; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc
swi 0x7B
die:
b die
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/Luma3DS.dat"
.word 0
.align 4
kernelcode_start:
; Disable MPU
ldr r0, =0x42078 ; alt vector select, enable itcm
mcr p15, 0, r0, c1, c0, 0
; Clean and flush data cache
mov r1, #0 ; segment counter
outer_loop:
mov r0, #0 ; line counter
inner_loop:
orr r2, r1, r0 ; generate segment and line address
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
add r0, #0x20 ; increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
; Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
; Jump to payload
ldr r0, =payload_addr
bx r0
.pool
.close

48
patches/svcGetCFWInfo.s Normal file
View File

@@ -0,0 +1,48 @@
;
; This file is part of Luma3DS
; Copyright (C) 2016 Aurora Wright, TuxSH
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
; Notices displayed by works containing it.
;
.arm.little
.create "build/svcGetCFWInfo.bin", 0
.arm
adr r1, infoStart
add r2, r0, #(infoEnd - infoStart)
loop:
ldrb r3, [r1], #1
strbt r3, [r0], #1
cmp r0, r2
blo loop
mov r0, #0
bx lr
.pool
infoStart:
.ascii "LUMA" ; magic
.word 0 ; version
.word 0 ; truncated commit hash
.word 0 ; config
infoEnd:
.close

144
patches/twl_k11modules.s Normal file
View File

@@ -0,0 +1,144 @@
;
; This file is part of Luma3DS
; Copyright (C) 2016 Aurora Wright, TuxSH
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
; Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
; reasonable legal notices or author attributions in that material or in the Appropriate Legal
; Notices displayed by works containing it.
;
.arm.little
.create "build/twl_k11modules.bin", 0
.align 4
.arm
patch:
; r4: Pointer to a pointer to the exheader of the current NCCH
; sp + 0xb0 - 0xa4: Pointer to the memory location where the NCCH text was loaded
add r3, sp, #(0xb0 - 0xa4)
add r1, sp, #(0xb0 - 0xac)
push {r0-r11, lr}
ldr r9, [r3] ; load the address of the code section
ldr r8, [r4] ; load the address of the exheader
ldr r7, [r8, #0x200] ; low titleID
ldr r6, =#0x000001ff
cmp r7, r6
bne end
ldr r7, =#0xabcdabcd ; offset of the dev launcher (will be replaced later)
add r7, r9
adr r5, patchesStart
add r6, r5, #(patchesEnd - patchesStart)
patchLoop:
ldrh r0, [r5, #4]
cmp r0, #0
moveq r4, r9
movne r4, r7
ldrh r2, [r5, #6]
add r1, r5, #8
ldr r0, [r5]
add r0, r4
blx memcmp
cmp r0, #0
bne skipPatch
ldrh r2, [r5, #6]
add r1, r5, #0x08
add r1, r2
ldr r0, [r5]
add r0, r4
blx memcpy
skipPatch:
ldrh r0, [r5, #6]
add r5, r5, #0x08
add r5, r0,lsl#1
cmp r5, r6
blo patchLoop
end:
pop {r0-r11, pc}
.align 2
.thumb
memcmp:
push {r4-r7, lr}
mov r4, #0
cmp_loop:
cmp r4, r2
bhs cmp_loop_end
ldrb r6, [r0, r4]
ldrb r7, [r1, r4]
add r4, #1
sub r6, r7
cmp r6, #0
beq cmp_loop
cmp_loop_end:
mov r0, r6
pop {r4-r7, pc}
memcpy:
push {r4-r5, lr}
mov r4, #0
copy_loop:
cmp r4, r2
bhs copy_loop_end
ldrb r5, [r1, r4]
strb r5, [r0, r4]
add r4, #1
b copy_loop
copy_loop_end:
pop {r4-r5, pc}
.align 4
; Available space for patches: 152 bytes on N3DS, 666 on O3DS
patchesStart:
; SCFG_EXT bit31 patches, based on https://github.com/ahezard/twl_firm_patcher (credits where they're due)
.word 0x07368 ; offset
.halfword 1 ; type (0: relative to the start of TwlBg's code; 1: relative to the start of the dev SRL launcher)
.halfword 4 ; size (must be a multiple of 4)
.byte 0x94, 0x09, 0xfc, 0xed ; expected data (decrypted = 0x08, 0x60, 0x87, 0x05)
.byte 0x24, 0x09, 0xbc, 0xe9 ; patched data (decrypted = 0xb8, 0x60, 0xc7, 0x01)
.word 0xa5888
.halfword 1
.halfword 8
.byte 0x83, 0x30, 0x2e, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x01, 0x1a, 0xe3, 0x08, 0x60, 0x87, 0x05)
.byte 0x83, 0x50, 0xf2, 0xa4, 0xb0, 0xe2, 0xc2, 0xd6 ; (decrypted = 0x02, 0x61, 0xc6, 0xe3, 0x08, 0x60, 0x87, 0xe5)
patchesEnd:
.pool
.close

98
pathchanger/pathchanger.c Normal file
View File

@@ -0,0 +1,98 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t u8;
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
{
const u8 *patternc = (const u8 *)pattern;
//Preprocessing
int table[256];
int i;
for(i = 0; i < 256; ++i)
table[i] = patternSize + 1;
for(i = 0; i < patternSize; ++i)
table[patternc[i]] = patternSize - i;
//Searching
int j = 0;
while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j;
j += table[startPos[j + patternSize]];
}
return NULL;
}
static int fsize(FILE *fp)
{
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
return size;
}
static void error(FILE *payload, const char *message)
{
fclose(payload);
printf("%s, are you sure you're using a Luma3DS payload?\n", message);
exit(0);
}
int main(int argc, char **argv)
{
if(argc == 1)
{
printf("Usage: %s <Luma3DS payload path>\n", argv[0]);
exit(0);
}
FILE *payload;
size_t size;
payload = fopen(argv[1], "rb+");
size = fsize(payload);
if(size > 0x20000)
error(payload, "The input file is too large");
u8 *buffer = (u8 *)malloc(size);
fread(buffer, 1, size, payload);
u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0};
u8 *found = memsearch(buffer, pattern, size, sizeof(pattern));
if(found == NULL)
{
free(buffer);
error(payload, "Pattern not found");
}
u8 input[38] = {0};
u8 payloadname[2 * (sizeof(input) - 1)] = {0};
printf("Enter the payload's path (37 characters max): ");
scanf("%37s", input);
unsigned int i;
for (i = 0; i < sizeof(input) - 1; i++)
payloadname[2 * i] = input[i];
memcpy(found + 12, payloadname, sizeof(payloadname));
rewind(payload);
fwrite(buffer, 1, size, payload);
free(buffer);
fclose(payload);
exit(0);
}

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python
# Requires Python >= 3.2 or >= 2.7
# This is part of Luma3DS
__author__ = "TuxSH"
__copyright__ = "Copyright (c) 2016 TuxSH"
__license__ = "GPLv3"
__version__ = "v1.0"
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Changes the path to Luma3DS for reboot patches")
parser.add_argument("payload", help="Path to the Luma3DS payload")
parser.add_argument("new_path", help="New Luma3DS payload path")
args = parser.parse_args()
data = b""
if len(args.new_path) > 37:
raise SystemExit("The new payload path is too large (37 characters max.)")
with open(args.payload, "rb") as f: data = bytearray(f.read())
if len(data) == 0: raise SystemExit("Could not read {0}".format(args.payload))
if len(data) > 0x20000:
raise SystemExit("The input file is too large, are you sure you're using a Luma3DS payload?")
found_index = data.find("sdmc:/".encode("utf-16-le"))
if found_index == -1:
raise SystemExit("The pattern was not found, are you sure you're usinga a Luma3DS payload?")
namebuf = args.new_path.encode("utf-16-le")
namebuf += b'\x00' * (74 - len(namebuf))
data[found_index + 12 : found_index + 12 + 74] = namebuf
with open(args.payload, "wb+") as f: f.write(data)

View File

@@ -1,221 +0,0 @@
.nds
.create "reboot.bin", 0
byteswritten equ 0x2000E000
externalFirm equ 0x2000A000
kernelCode equ 0x080F0000
buffer equ 0x24000000
fileOpen equ 0x4E45504F ;dummy
.arm
//Code jumps here right after the sprintf call
process9Reboot:
doPxi:
ldr r4, =0x44846
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0,#4]
.word 0xE1B01B81 //lsls r1, r1, #0x17
bmi readPxiLoop1
ldr r0, [r0,#0xC]
cmp r0, r4
bne doPxi
GetFirmPath:
add r0, sp, #0x3A8-0x70+0x24
ldr r1, [r0], #4
ldr r2, =0x00300030
cmp r1, r2
ldreq r1, [r0], #4
ldreq r2, =0x002F0032
cmpeq r1, r2
OpenFirm:
ldreq r1, =(FileName - OpenFirm - 12)
addeq r1, pc
addne r1, sp, #0x3A8-0x70
ldr r0, =externalFirm
moveq r2, #1
movne r2, #0
str r2, [r0]
mov r2, #1
add r0, r7, #8
ldr r6, =fileOpen
blx r6
SeekFirm:
ldr r0, =externalFirm
ldr r0, [r0]
cmp r0, #1
moveq r0, r7
ldreq r1, =byteswritten
ldreq r2, =buffer
ldreq r3, =0x0
ldreq r6, [sp,#0x3A8-0x198]
ldreq r6, [r6,#0x28] //fread function stored here
blxeq r6
ReadFirm:
mov r0, r7
ldr r1, =byteswritten
ldr r2, =buffer
ldr r3, =0x200000
ldr r6, [sp,#0x3A8-0x198]
ldr r6, [r6,#0x28] //fread function stored here
blx r6
KernelSetState:
mov r2, #0
mov r3, r2
mov r1, r2
mov r0, r2
.word 0xEF00007C //SVC 0x7C
GoToReboot:
ldr r0, =(KernelCodeStart - GoToReboot - 12)
add r0, pc
ldr r1, =kernelCode
ldr r2, =0x300
bl Memcpy
ldr r0, =kernelCode
.word 0xEF00007B //SVC 0x7B
InfiniteLoop:
b InfiniteLoop
Memcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
memcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT memcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
FileName:
.dcw "sdmc:/rei/patched_firmware.bin"
.word 0x0
.pool
// Kernel Code
.align 4
KernelCodeStart:
memorySetting:
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R12,c2,c0, 1
MRC p15, 0, R1,c3,c0, 0
MRC p15, 0, R2,c5,c0, 2
MRC p15, 0, R3,c5,c0, 3
LDR R4, =0x18000035
BIC R2, R2, #0xF0000
BIC R3, R3, #0xF0000
ORR R0, R0, #0x10
ORR R2, R2, #0x30000
ORR R3, R3, #0x30000
ORR R12, R12, #0x10
ORR R1, R1, #0x10
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R12,c2,c0, 1
MCR p15, 0, R1,c3,c0, 0
MCR p15, 0, R2,c5,c0, 2
MCR p15, 0, R3,c5,c0, 3
MCR p15, 0, R4,c6,c4, 0
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R1,c2,c0, 1
MRC p15, 0, R2,c3,c0, 0
ORR R0, R0, #0x20
ORR R1, R1, #0x20
ORR R2, R2, #0x20
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R1,c2,c0, 1
MCR p15, 0, R2,c3,c0, 0
copyFirmPartitions:
LDR R4, =buffer
ADD R3, R4, #0x40
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0x70
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0xA0
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0xD0
LDR R0, [R3]
CMP R0, #0
BEQ invalidateDataCache
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
invalidateDataCache:
MOV R2, #0
MOV R1, R2
loc_809460C:
MOV R0, #0
MOV R3, R2,LSL#30
loc_8094614:
ORR R12, R3, R0,LSL#5
MCR p15, 0, R1,c7,c10, 4
MCR p15, 0, R12,c7,c14, 2
ADD R0, R0, #1
CMP R0, #0x20
BCC loc_8094614
ADD R2, R2, #1
CMP R2, #4
BCC loc_809460C
jumpToEntrypoint:
MCR p15, 0, R1,c7,c10, 4
LDR R0, =0x42078
MCR p15, 0, R0,c1,c0, 0
MCR p15, 0, R1,c7,c5, 0
MCR p15, 0, R1,c7,c6, 0
MCR p15, 0, R1,c7,c10, 4
LDR R4, =buffer
MOV R1, #0x1FFFFFFC
LDR R2, [R4,#8]
STR R2, [R1]
LDR R0, [R4,#0xC]
BX R0
.pool
KernelMemcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
kmemcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT kmemcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
.pool
KernelCodeEnd:
.close

46
source/buttons.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#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 SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)

39
source/cache.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
/***
The following functions flush the data cache, then waits for all memory transfers to be finished.
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
- rebooting
- powering down
- setting the ARM11 entrypoint to execute a function
- jumping to a payload
***/
void flushEntireDCache(void); //actually: "clean and flush"
void flushDCacheRange(void *startAddress, u32 size);
void flushEntireICache(void);
void flushICacheRange(void *startAddress, u32 size);

89
source/cache.s Normal file
View File

@@ -0,0 +1,89 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
.text
.arm
.align 4
.global flushEntireDCache
.type flushEntireDCache, %function
flushEntireDCache:
@ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
@ Implemented in bootROM at address 0xffff0830
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
bx lr
.global flushDCacheRange
.type flushDCacheRange, %function
flushDCacheRange:
@ Implemented in bootROM at address 0xffff08a0
add r1, r0, r1 @ end address
bic r0, #0x1f @ align source address to cache line size (32 bytes)
flush_dcache_range_loop:
mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
add r0, #0x20
cmp r0, r1
blo flush_dcache_range_loop
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
bx lr
.global flushEntireICache
.type flushEntireICache, %function
flushEntireICache:
@ Implemented in bootROM at address 0xffff0ab4
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
.global flushICacheRange
.type flushICacheRange, %function
flushICacheRange:
@ Implemented in bootROM at address 0xffff0ac0
add r1, r0, r1 @ end address
bic r0, #0x1f @ align source address to cache line size (32 bytes)
flush_icache_range_loop:
mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding
add r0, #0x20
cmp r0, r1
blo flush_icache_range_loop
bx lr

198
source/config.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "config.h"
#include "utils.h"
#include "screen.h"
#include "draw.h"
#include "buttons.h"
void configureCFW(void)
{
initScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
const char *multiOptionsText[] = { "Screen brightness: 4( ) 3( ) 2( ) 1( )",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Use second EmuNAND as default",
"( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Display splash screen before payloads",
"( ) Use a PIN",
"( ) Enable experimental TwlBg patches" };
struct multiOption {
int posXs[4];
int posY;
u32 enabled;
} multiOptions[] = {
{ .posXs = {21, 26, 31, 36} },
{ .posXs = {17, 26, 32, 44} }
};
//Calculate the amount of the various kinds of options and pre-select the first single one
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
singleOptionsAmount = sizeof(singleOptionsText) / sizeof(char *),
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
selectedOption = multiOptionsAmount;
struct singleOption {
int posY;
bool enabled;
} singleOptions[singleOptionsAmount];
//Parse the existing options
for(u32 i = 0; i < multiOptionsAmount; i++)
multiOptions[i].enabled = MULTICONFIG(i);
for(u32 i = 0; i < singleOptionsAmount; i++)
singleOptions[i].enabled = CONFIG(i);
//Character to display a selected option
char selected = 'x';
int endPos = 42;
//Display all the multiple choice options in white
for(u32 i = 0; i < multiOptionsAmount; i++)
{
multiOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE);
drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
}
endPos += SPACING_Y / 2;
u32 color = COLOR_RED;
//Display all the normal options in white except for the first one
for(u32 i = 0; i < singleOptionsAmount; i++)
{
singleOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, color);
if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, color);
color = COLOR_WHITE;
}
u32 pressed = 0;
//Boring configuration menu
while(pressed != BUTTON_START)
{
do
{
pressed = waitInput();
}
while(!(pressed & MENU_BUTTONS));
if(pressed != BUTTON_A)
{
//Remember the previously selected option
u32 oldSelectedOption = selectedOption;
switch(pressed)
{
case BUTTON_UP:
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
break;
case BUTTON_DOWN:
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
break;
case BUTTON_LEFT:
selectedOption = 0;
break;
case BUTTON_RIGHT:
selectedOption = totalIndexes;
break;
default:
continue;
}
if(selectedOption == oldSelectedOption) continue;
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
if(oldSelectedOption < multiOptionsAmount)
{
drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
}
else
{
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
}
if(selectedOption < multiOptionsAmount)
drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED);
}
}
else
{
//The selected option's status changed, print the 'x's accordingly
if(selectedOption < multiOptionsAmount)
{
u32 oldEnabled = multiOptions[selectedOption].enabled;
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
if(!selectedOption)
updateBrightness(multiOptions[selectedOption].enabled);
}
else
{
bool oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
}
}
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
if(selectedOption < multiOptionsAmount)
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
if(singleOptions[singleSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
}
}
//Preserve the last-used boot options (last 12 bits)
config &= 0x3F;
//Parse and write the new configuration
for(u32 i = 0; i < multiOptionsAmount; i++)
config |= multiOptions[i].enabled << (i * 2 + 6);
for(u32 i = 0; i < singleOptionsAmount; i++)
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
//Wait for the pressed buttons to change
while(HID_PAD == BUTTON_START);
}

33
source/config.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
#define CONFIG(a) (((config >> (a + 16)) & 1) != 0)
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((config >> a) & b)
extern u32 config;
void configureCFW(void);

View File

@@ -1,422 +1,470 @@
// From http://github.com/b1l1s/ctr /*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* Crypto libs from http://github.com/b1l1s/ctr
*/
#include "crypto.h" #include "crypto.h"
#include <stddef.h>
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
#include "fatfs/ff.h"
/**************************************************************** /****************************************************************
* Crypto Libs * Crypto libs
****************************************************************/ ****************************************************************/
/* original version by megazig */ /* original version by megazig */
#ifndef __thumb__ #ifndef __thumb__
#define BSWAP32(x) {\ #define BSWAP32(x) {\
__asm__\ __asm__\
(\ (\
"eor r1, %1, %1, ror #16\n\t"\ "eor r1, %1, %1, ror #16\n\t"\
"bic r1, r1, #0xFF0000\n\t"\ "bic r1, r1, #0xFF0000\n\t"\
"mov %0, %1, ror #8\n\t"\ "mov %0, %1, ror #8\n\t"\
"eor %0, %0, r1, lsr #8\n\t"\ "eor %0, %0, r1, lsr #8\n\t"\
:"=r"(x)\ :"=r"(x)\
:"0"(x)\ :"0"(x)\
:"r1"\ :"r1"\
);\ );\
}; };
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ #define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\ __asm__\
(\ (\
"adds %0, %4\n\t"\ "adds %0, %4\n\t"\
"addcss %1, %1, #1\n\t"\ "addcss %1, %1, #1\n\t"\
"addcss %2, %2, #1\n\t"\ "addcss %2, %2, #1\n\t"\
"addcs %3, %3, #1\n\t"\ "addcs %3, %3, #1\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\ : "r"(u32_0)\
: "cc"\ : "cc"\
);\ );\
} }
#else #else
#define BSWAP32(x) {x = __builtin_bswap32(x);} #define BSWAP32(x) {x = __builtin_bswap32(x);}
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ #define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\ __asm__\
(\ (\
"mov r4, #0\n\t"\ "mov r4, #0\n\t"\
"add %0, %0, %4\n\t"\ "add %0, %0, %4\n\t"\
"adc %1, %1, r4\n\t"\ "adc %1, %1, r4\n\t"\
"adc %2, %2, r4\n\t"\ "adc %2, %2, r4\n\t"\
"adc %3, %3, r4\n\t"\ "adc %3, %3, r4\n\t"\
: "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
: "r"(u32_0)\ : "r"(u32_0)\
: "cc", "r4"\ : "cc", "r4"\
);\ );\
} }
#endif /*__thumb__*/ #endif /*__thumb__*/
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode) static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
{ {
if(keyslot <= 0x03) return; // Ignore TWL keys for now if(keyslot <= 0x03) return; // Ignore TWL keys for now
u32* key32 = (u32*)key; u32 *key32 = (u32 *)key;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
REG_AESKEYFIFO[keyType] = key32[0]; REG_AESKEYFIFO[keyType] = key32[0];
REG_AESKEYFIFO[keyType] = key32[1]; REG_AESKEYFIFO[keyType] = key32[1];
REG_AESKEYFIFO[keyType] = key32[2]; REG_AESKEYFIFO[keyType] = key32[2];
REG_AESKEYFIFO[keyType] = key32[3]; REG_AESKEYFIFO[keyType] = key32[3];
} }
void aes_use_keyslot(u8 keyslot) static void aes_use_keyslot(u8 keyslot)
{ {
if(keyslot > 0x3F) if(keyslot > 0x3F)
return; return;
*REG_AESKEYSEL = keyslot; *REG_AESKEYSEL = keyslot;
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
} }
void aes_setiv(const void* iv, u32 mode) static void aes_setiv(const void *iv, u32 mode)
{ {
const u32* iv32 = (const u32*)iv; const u32 *iv32 = (const u32 *)iv;
*REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
// Word order for IV can't be changed in REG_AESCNT and always default to reversed // Word order for IV can't be changed in REG_AESCNT and always default to reversed
if(mode & AES_INPUT_NORMAL) if(mode & AES_INPUT_NORMAL)
{ {
REG_AESCTR[0] = iv32[3]; REG_AESCTR[0] = iv32[3];
REG_AESCTR[1] = iv32[2]; REG_AESCTR[1] = iv32[2];
REG_AESCTR[2] = iv32[1]; REG_AESCTR[2] = iv32[1];
REG_AESCTR[3] = iv32[0]; REG_AESCTR[3] = iv32[0];
} }
else else
{ {
REG_AESCTR[0] = iv32[0]; REG_AESCTR[0] = iv32[0];
REG_AESCTR[1] = iv32[1]; REG_AESCTR[1] = iv32[1];
REG_AESCTR[2] = iv32[2]; REG_AESCTR[2] = iv32[2];
REG_AESCTR[3] = iv32[3]; REG_AESCTR[3] = iv32[3];
} }
} }
void aes_advctr(void* ctr, u32 val, u32 mode) static void aes_advctr(void *ctr, u32 val, u32 mode)
{ {
u32* ctr32 = (u32*)ctr; u32 *ctr32 = (u32 *)ctr;
int i; int i;
if(mode & AES_INPUT_BE) if(mode & AES_INPUT_BE)
{ {
for(i = 0; i < 4; ++i) // Endian swap for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]); BSWAP32(ctr32[i]);
} }
if(mode & AES_INPUT_NORMAL) if(mode & AES_INPUT_NORMAL)
{ {
ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
} }
else else
{ {
ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
} }
if(mode & AES_INPUT_BE) if(mode & AES_INPUT_BE)
{ {
for(i = 0; i < 4; ++i) // Endian swap for(i = 0; i < 4; ++i) // Endian swap
BSWAP32(ctr32[i]); BSWAP32(ctr32[i]);
} }
} }
void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode) static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
{ {
u32* ctr32 = (u32*)ctr; u32 *ctr32 = (u32 *)ctr;
int i; int i;
if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
{ {
for(i = 0; i < 4; ++i) for(i = 0; i < 4; ++i)
BSWAP32(ctr32[i]); BSWAP32(ctr32[i]);
} }
if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
{ {
u32 temp = ctr32[0]; u32 temp = ctr32[0];
ctr32[0] = ctr32[3]; ctr32[0] = ctr32[3];
ctr32[3] = temp; ctr32[3] = temp;
temp = ctr32[1]; temp = ctr32[1];
ctr32[1] = ctr32[2]; ctr32[1] = ctr32[2];
ctr32[2] = temp; ctr32[2] = temp;
} }
} }
void aes_batch(void* dst, const void* src, u32 blockCount) static void aes_batch(void *dst, const void *src, u32 blockCount)
{ {
*REG_AESBLKCNT = blockCount << 16; *REG_AESBLKCNT = blockCount << 16;
*REG_AESCNT |= AES_CNT_START; *REG_AESCNT |= AES_CNT_START;
const u32* src32 = (const u32*)src; const u32 *src32 = (const u32 *)src;
u32* dst32 = (u32*)dst; u32 *dst32 = (u32 *)dst;
u32 wbc = blockCount; u32 wbc = blockCount;
u32 rbc = blockCount; u32 rbc = blockCount;
while(rbc) while(rbc)
{ {
if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
{ {
*REG_AESWRFIFO = *src32++; *REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++; *REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++; *REG_AESWRFIFO = *src32++;
*REG_AESWRFIFO = *src32++; *REG_AESWRFIFO = *src32++;
wbc--; wbc--;
} }
if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
{ {
*dst32++ = *REG_AESRDFIFO; *dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO; *dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO; *dst32++ = *REG_AESRDFIFO;
*dst32++ = *REG_AESRDFIFO; *dst32++ = *REG_AESRDFIFO;
rbc--; rbc--;
} }
} }
} }
void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode) static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
{ {
*REG_AESCNT = mode | *REG_AESCNT = mode |
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
u32 blocks; u32 blocks;
while(blockCount != 0) while(blockCount != 0)
{ {
if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
&& (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
aes_setiv(iv, ivMode); aes_setiv(iv, ivMode);
blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
// Save the last block for the next decryption CBC batch's iv // Save the last block for the next decryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
{ {
memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
} }
// Process the current batch // Process the current batch
aes_batch(dst, src, blocks); aes_batch(dst, src, blocks);
// Save the last block for the next encryption CBC batch's iv // Save the last block for the next encryption CBC batch's iv
if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
{ {
memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
} }
// Advance counter for CTR mode // Advance counter for CTR mode
else if((mode & AES_ALL_MODES) == AES_CTR_MODE) else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
aes_advctr(iv, blocks, ivMode); aes_advctr(iv, blocks, ivMode);
src += blocks * AES_BLOCK_SIZE; src += blocks * AES_BLOCK_SIZE;
dst += blocks * AES_BLOCK_SIZE; dst += blocks * AES_BLOCK_SIZE;
blockCount -= blocks; blockCount -= blocks;
} }
} }
void sha_wait_idle() static void sha_wait_idle()
{ {
while(*REG_SHA_CNT & 1); while(*REG_SHA_CNT & 1);
} }
void sha(void* res, const void* src, u32 size, u32 mode) static void sha(void *res, const void *src, u32 size, u32 mode)
{ {
sha_wait_idle(); sha_wait_idle();
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
const u32* src32 = (const u32*)src; const u32 *src32 = (const u32 *)src;
int i; int i;
while(size >= 0x40) while(size >= 0x40)
{ {
sha_wait_idle(); sha_wait_idle();
for(i = 0; i < 4; ++i) for(i = 0; i < 4; ++i)
{ {
*REG_SHA_INFIFO = *src32++; *REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++; *REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++; *REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++; *REG_SHA_INFIFO = *src32++;
} }
size -= 0x40; size -= 0x40;
} }
sha_wait_idle(); sha_wait_idle();
memcpy((void*)REG_SHA_INFIFO, src32, size); memcpy((void *)REG_SHA_INFIFO, src32, size);
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHA_CNT & SHA_FINAL_ROUND); while(*REG_SHA_CNT & SHA_FINAL_ROUND);
sha_wait_idle(); sha_wait_idle();
u32 hashSize = SHA_256_HASH_SIZE; u32 hashSize = SHA_256_HASH_SIZE;
if(mode == SHA_224_MODE) if(mode == SHA_224_MODE)
hashSize = SHA_224_HASH_SIZE; hashSize = SHA_224_HASH_SIZE;
else if(mode == SHA_1_MODE) else if(mode == SHA_1_MODE)
hashSize = SHA_1_HASH_SIZE; hashSize = SHA_1_HASH_SIZE;
memcpy(res, (void*)REG_SHA_HASH, hashSize); memcpy(res, (void *)REG_SHA_HASH, hashSize);
}
void rsa_wait_idle()
{
while(*REG_RSA_CNT & 1);
}
void rsa_use_keyslot(u32 keyslot)
{
*REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4);
}
void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode)
{
rsa_wait_idle();
*REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4) | RSA_IO_BE | RSA_IO_NORMAL;
u32 size = mode * 4;
volatile u32* keyslotCnt = REG_RSA_SLOT0 + (keyslot << 4);
keyslotCnt[0] &= ~(RSA_SLOTCNT_KEY_SET | RSA_SLOTCNT_WPROTECT);
keyslotCnt[1] = mode;
memcpy((void*)REG_RSA_MOD_END - size, mod, size);
if(exp == NULL)
{
size -= 4;
while(size)
{
*REG_RSA_EXPFIFO = 0;
size -= 4;
}
*REG_RSA_EXPFIFO = 0x01000100; // 0x00010001 byteswapped
}
else
{
const u32* exp32 = (const u32*)exp;
while(size)
{
*REG_RSA_EXPFIFO = *exp32++;
size -= 4;
}
}
}
int rsa_iskeyset(u32 keyslot)
{
return *(REG_RSA_SLOT0 + (keyslot << 4)) & 1;
}
void rsa(void* dst, const void* src, u32 size)
{
u32 keyslot = (*REG_RSA_CNT & RSA_CNT_KEYSLOTS) >> 4;
if(rsa_iskeyset(keyslot) == 0)
return;
rsa_wait_idle();
*REG_RSA_CNT |= RSA_IO_BE | RSA_IO_NORMAL;
// Pad the message with zeroes so that it's a multiple of 8
// and write the message with the end aligned with the register
u32 padSize = ((size + 7) & ~7) - size;
memset((void*)REG_RSA_TXT_END - (size + padSize), 0, padSize);
memcpy((void*)REG_RSA_TXT_END - size, src, size);
// Start
*REG_RSA_CNT |= RSA_CNT_START;
rsa_wait_idle();
memcpy(dst, (void*)REG_RSA_TXT_END - size, size);
}
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode)
{
u8 dataHash[SHA_256_HASH_SIZE];
sha(dataHash, data, size, SHA_256_MODE);
u8 decSig[0x100]; // Way too big, need to request a work area
u32 sigSize = mode * 4;
rsa(decSig, sig, sigSize);
return memcmp(dataHash, decSig + (sigSize - SHA_256_HASH_SIZE), SHA_256_HASH_SIZE) == 0;
} }
/**************************************************************** /****************************************************************
* Nand/FIRM Crypto stuff * NAND/FIRM crypto
****************************************************************/ ****************************************************************/
//Get Nand CTR key static u8 __attribute__((aligned(4))) nandCTR[0x10];
void getNandCTR(u8 *buf, u8 console) { static u8 nandSlot;
u8 *addr = console ? (u8*)0x080D8BBC : (u8*)0x080D797C;
u8 keyLen = 0x10; //CTR length static u32 fatStart;
addr += 0x0F;
while (keyLen --) { *(buf++) = *(addr--); } //Initialize the CTRNAND crypto
void ctrNandInit(void)
{
u8 __attribute__((aligned(4))) cid[0x10];
u8 __attribute__((aligned(4))) shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE);
memcpy(nandCTR, shaSum, 0x10);
if(isN3DS)
{
u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
fatStart = 0x5CAD7;
}
else
{
nandSlot = 0x04;
fatStart = 0x5CAE5;
}
} }
//Read firm0 from NAND and write to buffer //Read and decrypt from the selected CTRNAND
void nandFirm0(u8 *outbuf, const u32 size, u8 console){ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
u8 CTR[0x10]; {
getNandCTR(CTR, console); u8 __attribute__((aligned(4))) tmpCTR[0x10];
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL); memcpy(tmpCTR, nandCTR, 0x10);
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf); aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x06);
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); //Read
u32 result;
if(firmSource == FIRMWARE_SYSNAND)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else
{
sector += emuOffset;
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
}
//Decrypt
aes_use_keyslot(nandSlot);
aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
return result;
} }
//Emulates the Arm9loader process //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
void arm9loader(void *armHdr, u8 mode){ void setRSAMod0DerivedKeys(void)
//Nand key#2 (0x12C10) {
u8 key2[0x10] = { if(!isDevUnit)
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0 {
}; const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
when non-zero it clears this block and continues to do the key generation.
Otherwise when this block was already all-zero, it immediately returns. */
memset32((void *)0x01FFCD00, 0, 0x10);
}
}
//Decrypt a FIRM ExeFS
void decryptExeFs(u8 *inbuf)
{
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
u8 ncchCTR[0x10] = {0};
for(u32 i = 0; i < 8; i++)
ncchCTR[7 - i] = *(inbuf + 0x108 + i);
ncchCTR[8] = 2;
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C);
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
/* ARM9Loader replacement
Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 */
void arm9Loader(u8 *arm9Section)
{
//Determine the arm9loader version
u32 a9lVersion;
switch(arm9Section[0x53])
{
case 0xFF:
a9lVersion = 0;
break;
case '1':
a9lVersion = 1;
break;
default:
a9lVersion = 2;
break;
}
//Firm keys //Firm keys
u8 keyX[0x10]; u8 __attribute__((aligned(4))) keyY[0x10];
u8 keyY[0x10]; u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
u8 CTR[0x10]; u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
u32 slot = mode ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption
//Setup keys needed for arm9bin decryption memcpy(keyY, arm9Section + 0x10, 0x10);
memcpy((u8*)keyY, (void *)((uintptr_t)armHdr+0x10), 0x10); memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
memcpy((u8*)CTR, (void *)((uintptr_t)armHdr+0x20), 0x10);
u32 size = atoi((void *)((uintptr_t)armHdr+0x30)); //Calculate the size of the ARM9 binary
u32 arm9BinSize = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
if(a9lVersion)
{
u8 __attribute__((aligned(4))) keyX[0x10];
if(!isDevUnit)
{
const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
}
if(mode){
//Set 0x11 to key2 for the arm9bin and misc keys
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes((u8*)keyX, (void *)((uintptr_t)armHdr+0x60), 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, (u8*)keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
aes_setkey(slot, (u8*)keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv((u8*)CTR, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(slot); aes_use_keyslot(arm9BinSlot);
//Decrypt arm9bin //Decrypt arm9bin
aes((void *)(armHdr+0x800), (void *)(armHdr+0x800), size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set >=9.6 KeyXs
if(a9lVersion == 2 && !isDevUnit)
{
u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
u8 __attribute__((aligned(4))) decKey[0x10];
if(mode){
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
u8* decKey = (void *)((uintptr_t)armHdr+0x89824);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
for(slot = 0x19; slot < 0x20; slot++) { for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); {
aes(decKey, (void *)((uintptr_t)armHdr+0x89814), 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, (u8*)decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(u8 *)((void *)((uintptr_t)armHdr+0x89814+0xF)) += 1;
} }
} }
}
void computePINHash(u8 out[32], u8 *in, u32 blockCount)
{
u8 __attribute__((aligned(4))) cid[0x10];
u8 __attribute__((aligned(4))) cipherText[0x10];
sdmmc_get_cid(1, (u32 *)cid);
aes_use_keyslot(4); // console-unique keyslot which keys are set by the Arm9 bootROM
aes(cipherText, in, blockCount, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
sha(out, cipherText, 0x10, SHA_256_MODE);
} }

View File

@@ -1,137 +1,113 @@
// From http://github.com/b1l1s/ctr /*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#ifndef __CRYPTO_H /*
#define __CRYPTO_H * Crypto libs from http://github.com/b1l1s/ctr
*/
#pragma once
#include <stdint.h>
#include "types.h" #include "types.h"
#define FIRM_TYPE_ARM9 0
#define FIRM_TYPE_ARM11 1
#define MEDIA_UNITS 0x200
#define NCCH_MAGIC (0x4843434E)
#define NCSD_MAGIC (0x4453434E)
#define FIRM_MAGIC (0x4D524946)
#define ARM9BIN_MAGIC (0x47704770)
/**************************AES****************************/ /**************************AES****************************/
#define REG_AESCNT ((volatile u32*)0x10009000) #define REG_AESCNT ((vu32 *)0x10009000)
#define REG_AESBLKCNT ((volatile u32*)0x10009004) #define REG_AESBLKCNT ((vu32 *)0x10009004)
#define REG_AESWRFIFO ((volatile u32*)0x10009008) #define REG_AESWRFIFO ((vu32 *)0x10009008)
#define REG_AESRDFIFO ((volatile u32*)0x1000900C) #define REG_AESRDFIFO ((vu32 *)0x1000900C)
#define REG_AESKEYSEL ((volatile u8 *)0x10009010) #define REG_AESKEYSEL ((vu8 *)0x10009010)
#define REG_AESKEYCNT ((volatile u8 *)0x10009011) #define REG_AESKEYCNT ((vu8 *)0x10009011)
#define REG_AESCTR ((volatile u32*)0x10009020) #define REG_AESCTR ((vu32 *)0x10009020)
#define REG_AESKEYFIFO ((volatile u32*)0x10009100) #define REG_AESKEYFIFO ((vu32 *)0x10009100)
#define REG_AESKEYXFIFO ((volatile u32*)0x10009104) #define REG_AESKEYXFIFO ((vu32 *)0x10009104)
#define REG_AESKEYYFIFO ((volatile u32*)0x10009108) #define REG_AESKEYYFIFO ((vu32 *)0x10009108)
#define AES_CCM_DECRYPT_MODE (0u << 27) #define AES_CCM_DECRYPT_MODE (0u << 27)
#define AES_CCM_ENCRYPT_MODE (1u << 27) #define AES_CCM_ENCRYPT_MODE (1u << 27)
#define AES_CTR_MODE (2u << 27) #define AES_CTR_MODE (2u << 27)
#define AES_CTR_MODE (2u << 27) #define AES_CTR_MODE (2u << 27)
#define AES_CBC_DECRYPT_MODE (4u << 27) #define AES_CBC_DECRYPT_MODE (4u << 27)
#define AES_CBC_ENCRYPT_MODE (5u << 27) #define AES_CBC_ENCRYPT_MODE (5u << 27)
#define AES_ECB_DECRYPT_MODE (6u << 27) #define AES_ECB_DECRYPT_MODE (6u << 27)
#define AES_ECB_ENCRYPT_MODE (7u << 27) #define AES_ECB_ENCRYPT_MODE (7u << 27)
#define AES_ALL_MODES (7u << 27) #define AES_ALL_MODES (7u << 27)
#define AES_CNT_START 0x80000000 #define AES_CNT_START 0x80000000
#define AES_CNT_INPUT_ORDER 0x02000000 #define AES_CNT_INPUT_ORDER 0x02000000
#define AES_CNT_OUTPUT_ORDER 0x01000000 #define AES_CNT_OUTPUT_ORDER 0x01000000
#define AES_CNT_INPUT_ENDIAN 0x00800000 #define AES_CNT_INPUT_ENDIAN 0x00800000
#define AES_CNT_OUTPUT_ENDIAN 0x00400000 #define AES_CNT_OUTPUT_ENDIAN 0x00400000
#define AES_CNT_FLUSH_READ 0x00000800 #define AES_CNT_FLUSH_READ 0x00000800
#define AES_CNT_FLUSH_WRITE 0x00000400 #define AES_CNT_FLUSH_WRITE 0x00000400
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) #define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
#define AES_INPUT_LE 0 #define AES_INPUT_LE 0
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) #define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
#define AES_INPUT_REVERSED 0 #define AES_INPUT_REVERSED 0
#define AES_TEMP_KEYSLOT 0x11 #define AES_BLOCK_SIZE 0x10
#define AES_BLOCK_SIZE 0x10 #define AES_KEYCNT_WRITE (1 << 0x7)
#define AES_KEYNORMAL 0
#define AES_KEYCNT_WRITE (1 << 0x7) #define AES_KEYX 1
#define AES_KEYNORMAL 0 #define AES_KEYY 2
#define AES_KEYX 1
#define AES_KEYY 2
/**************************SHA****************************/ /**************************SHA****************************/
#define REG_SHA_CNT ((volatile u32*)0x1000A000) #define REG_SHA_CNT ((vu32 *)0x1000A000)
#define REG_SHA_BLKCNT ((volatile u32*)0x1000A004) #define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
#define REG_SHA_HASH ((volatile u32*)0x1000A040) #define REG_SHA_HASH ((vu32 *)0x1000A040)
#define REG_SHA_INFIFO ((volatile u32*)0x1000A080) #define REG_SHA_INFIFO ((vu32 *)0x1000A080)
#define SHA_CNT_STATE 0x00000003 #define SHA_CNT_STATE 0x00000003
#define SHA_CNT_UNK2 0x00000004 #define SHA_CNT_UNK2 0x00000004
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 #define SHA_CNT_OUTPUT_ENDIAN 0x00000008
#define SHA_CNT_MODE 0x00000030 #define SHA_CNT_MODE 0x00000030
#define SHA_CNT_ENABLE 0x00010000 #define SHA_CNT_ENABLE 0x00010000
#define SHA_CNT_ACTIVE 0x00020000 #define SHA_CNT_ACTIVE 0x00020000
#define SHA_HASH_READY 0x00000000 #define SHA_HASH_READY 0x00000000
#define SHA_NORMAL_ROUND 0x00000001 #define SHA_NORMAL_ROUND 0x00000001
#define SHA_FINAL_ROUND 0x00000002 #define SHA_FINAL_ROUND 0x00000002
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN #define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
#define SHA_OUTPUT_LE 0 #define SHA_OUTPUT_LE 0
#define SHA_256_MODE 0 #define SHA_256_MODE 0
#define SHA_224_MODE 0x00000010 #define SHA_224_MODE 0x00000010
#define SHA_1_MODE 0x00000020 #define SHA_1_MODE 0x00000020
#define SHA_256_HASH_SIZE (256 / 8) #define SHA_256_HASH_SIZE (256 / 8)
#define SHA_224_HASH_SIZE (224 / 8) #define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8) #define SHA_1_HASH_SIZE (160 / 8)
/**************************RSA****************************/ extern u32 emuOffset;
#define REG_RSA_CNT ((volatile u32*)0x1000B000) extern bool isN3DS;
#define REG_RSA_SLOT0 ((volatile u32*)0x1000B100) extern bool isDevUnit;
#define REG_RSA_SLOT1 ((volatile u32*)0x1000B110) extern FirmwareSource firmSource;
#define REG_RSA_SLOT2 ((volatile u32*)0x1000B120)
#define REG_RSA_SLOT3 ((volatile u32*)0x1000B130)
#define REG_RSA_EXPFIFO ((volatile u32*)0x1000B200)
#define REG_RSA_MOD_END ((volatile u32*)0x1000B500)
#define REG_RSA_TXT_END ((volatile u32*)0x1000B900)
#define RSA_CNT_START 0x00000001 void ctrNandInit(void);
#define RSA_CNT_KEYSLOTS 0x000000F0 u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
#define RSA_CNT_IO_ENDIAN 0x00000100 void setRSAMod0DerivedKeys(void);
#define RSA_CNT_IO_ORDER 0x00000200 void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section);
#define RSA_SLOTCNT_KEY_SET 0x00000001 void computePINHash(u8 out[32], u8 *in, u32 blockCount);
#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect
#define RSA_IO_BE RSA_CNT_IO_ENDIAN
#define RSA_IO_LE 0
#define RSA_IO_NORMAL RSA_CNT_IO_ORDER
#define RSA_IO_REVERSED 0
#define RSA_TEMP_KEYSLOT 0
#define RSA_1024_MODE 0x20
#define RSA_2048_MODE 0x40
//Crypto Libs
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode);
void aes_use_keyslot(u8 keyslot);
void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode);
void aes_setiv(const void* iv, u32 mode);
void aes_advctr(void* ctr, u32 val, u32 mode);
void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode);
void aes_batch(void* dst, const void* src, u32 blockCount);
void sha(void* res, const void* src, u32 size, u32 mode);
void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode);
void rsa_use_keyslot(u32 keyslot);
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
//NAND/FIRM stuff
void nandFirm0(u8 *outbuf, const u32 size, u8 console);
void arm9loader(void *armHdr, u8 mode);
#endif /*__CRYPTO_H*/

View File

@@ -1,25 +1,101 @@
/* /*
* draw.c * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* Code to print to the screen by mid-kid @CakesFW
* https://github.com/mid-kid/CakesForeveryWan/
*/ */
#include "draw.h" #include "draw.h"
#include "screen.h"
#include "utils.h"
#include "fs.h" #include "fs.h"
#include "memory.h" #include "font.h"
static struct fb* fb = (struct fb*) 0x23FFFE00; static inline int strlen(const char *string)
{
char *stringEnd = (char *)string;
void clearScreen(void){ while(*stringEnd) stringEnd++;
memset(fb->top_left, 0, 0x38400);
memset(fb->top_right, 0, 0x38400); return stringEnd - string;
memset(fb->bottom, 0, 0x38400);
} }
void loadSplash(void){ bool loadSplash(void)
//Check if it's a no-screen-init A9LH boot via PDN_GPU_CNT {
if (*((u8*)0x10141200) == 0x1) return; //Don't delay boot nor init the screens if no splash image is on the SD
clearScreen(); if(getFileSize("/luma/splash.bin") + getFileSize("/luma/splashbottom.bin") == 0)
if(fileRead(fb->top_left, "/rei/splash.bin", 0x46500) != 0) return; return false;
unsigned i,t; for(t=220;t>0;t--){for(i=0xFFFF;i>0;i--);}; //Ghetto sleep func
initScreens();
fileRead(fb->top_left, "/luma/splash.bin");
fileRead(fb->bottom, "/luma/splashbottom.bin");
chrono(3);
return true;
}
void drawCharacter(char character, int posX, int posY, u32 color)
{
u8 *const select = fb->top_left;
for(int y = 0; y < 8; y++)
{
char charPos = font[character * 8 + y];
for(int x = 7; x >= 0; x--)
if ((charPos >> x) & 1)
{
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
select[screenPos] = color >> 16;
select[screenPos + 1] = color >> 8;
select[screenPos + 2] = color;
}
}
}
int drawString(const char *string, int posX, int posY, u32 color)
{
for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
{
if(string[i] == '\n')
{
posY += SPACING_Y;
line_i = 0;
i++;
}
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
{
// Make sure we never get out of the screen.
posY += SPACING_Y;
line_i = 2; //Little offset so we know the same string continues.
if(string[i] == ' ') i++; //Spaces at the start look weird
}
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
}
return posY;
} }

View File

@@ -1,15 +1,45 @@
/* /*
* draw.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
/*
* Code to print to the screen by mid-kid @CakesFW
* https://github.com/mid-kid/CakesForeveryWan/
*/
#pragma once
#include "types.h" #include "types.h"
struct fb { #define SCREEN_TOP_WIDTH 400
u8 *top_left; #define SCREEN_TOP_HEIGHT 240
u8 *top_right;
u8 *bottom;
};
void loadSplash(void); #define SPACING_Y 10
#define SPACING_X 8
#define COLOR_TITLE 0xFF9900
#define COLOR_WHITE 0xFFFFFF
#define COLOR_RED 0x0000FF
#define COLOR_BLACK 0x000000
bool loadSplash(void);
void drawCharacter(char character, int posX, int posY, u32 color);
int drawString(const char *string, int posX, int posY, u32 color);

View File

@@ -1,56 +1,132 @@
/* /*
* emunand.c * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
#include "emunand.h" #include "emunand.h"
#include "memory.h" #include "memory.h"
#include "fatfs/ff.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
#include "../build/emunandpatch.h"
static u8 *temp = (u8*)0x24300000; void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND)
{
static u8 temp[0x200];
void getEmunandSect(u32 *off, u32 *head){ const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandSize = getMMCDevice(0)->total_size; u32 nandOffset = *emuNAND == FIRMWARE_EMUNAND ? 0 :
if (sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0) { (nandSize > 0x200000 ? 0x400000 : 0x200000);
if (*(u32*)(temp + 0x100) == NCSD_MAGIC) {
*off = 0; //Check for RedNAND
*head = nandSize; if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) &&
} *(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset + 1;
*head = nandOffset + 1;
}
//Check for Gateway emuNAND
else if(!sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) &&
*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset;
*head = nandOffset + nandSize;
}
/* Fallback to the first emuNAND if there's no second one,
or to SysNAND if there isn't any */
else
{
*emuNAND = (*emuNAND == FIRMWARE_EMUNAND2) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
if(*emuNAND) locateEmuNAND(off, head, emuNAND);
} }
} }
void getSDMMC(void *pos, u32 *off, u32 size){ static inline void *getEmuCode(u8 *pos, u32 size)
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9
return memsearch(pos + 0x13500, pattern, size - 0x13500, 6) + 0x455;
}
static inline u32 getSDMMC(u8 *pos, u32 size)
{
//Look for struct code //Look for struct code
unsigned char pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
*off = (u32)memsearch(pos, pattern, size, 4) - 1; const u8 *off = memsearch(pos, pattern, size, 4);
//Get DCD values return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
unsigned char buf[4];
int p;
u32 addr = 0,
additive = 0;
memcpy((void*)buf, (void*)(*off+0x0A), 4);
for (p = 0; p < 4; p++) addr |= ((u32) buf[p]) << (8 * p);
memcpy((void*)buf, (void*)(*off+0x0E), 4);
for (p = 0; p < 4; p++) additive |= ((u32) buf[p]) << (8 * p);
//Return result
*off = addr + additive;
} }
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff){ static inline void patchNANDRW(u8 *pos, u32 size, u32 branchOffset)
{
const u16 nandRedir[2] = {0x4C00, 0x47A0};
//Look for read/write code //Look for read/write code
unsigned char pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
*writeOff = (u32)memsearch(pos, pattern, size, 4) - 6; u16 *readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3,
*readOff = (u32)memsearch((void *)(*writeOff - 0x1000), pattern, 0x1000, 4) - 6; *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, 4) - 3;
*readOffset = nandRedir[0];
readOffset[1] = nandRedir[1];
((u32 *)readOffset)[1] = branchOffset;
*writeOffset = nandRedir[0];
writeOffset[1] = nandRedir[1];
((u32 *)writeOffset)[1] = branchOffset;
} }
void getMPU(void *pos, u32 *off, u32 size){ static inline void patchMPU(u8 *pos, u32 size)
//Look for MPU pattern {
unsigned char pattern[] = {0x03, 0x00, 0x24, 0x00}; const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
*off = (u32)memsearch(pos, pattern, size, 4); //Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
u32 *off = (u32 *)memsearch(pos, pattern, size, 4);
off[0] = mpuPatch[0];
off[6] = mpuPatch[1];
off[9] = mpuPatch[2];
}
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive)
{
//Copy emuNAND code
void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize);
memcpy(emuCodeOffset, emunand, emunand_size);
//Add the data of the found emuNAND
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4),
*pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
*pos_offset = emuOffset;
*pos_header = emuHeader;
//Find and add the SDMMC struct
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
*pos_sdmmc = getSDMMC(process9Offset, process9Size);
//Add emuNAND hooks
u32 branchOffset = (u32)emuCodeOffset - branchAdditive;
patchNANDRW(process9Offset, process9Size, branchOffset);
//Set MPU for emu code region
patchMPU(arm9Section, arm9SectionSize);
} }

View File

@@ -1,19 +1,30 @@
/* /*
* emunand.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
#ifndef EMU_INC #pragma once
#define EMU_INC
#include "types.h" #include "types.h"
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC 0x4453434E
void getEmunandSect(u32 *off, u32 *head); void locateEmuNAND(u32 *off, u32 *head, FirmwareSource *emuNAND);
void getSDMMC(void *pos, u32 *off, u32 size); void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff);
void getMPU(void *pos, u32 *off, u32 size);
#endif

447
source/fatfs/history.txt → source/fatfs/00history.txt Normal file → Executable file
View File

@@ -1,180 +1,267 @@
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
Revision history of FatFs module Revision history of FatFs module
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
R0.00 (February 26, 2006) R0.00 (February 26, 2006)
Prototype.
Prototype.
R0.01 (April 29, 2006)
First stable version.
R0.01 (April 29, 2006)
R0.02 (June 01, 2006) The first release.
Added FAT12 support.
Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.02 (June 01, 2006)
R0.02a (June 10, 2006) Added FAT12 support.
Added a configuration option (_FS_MINIMUM). Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.03 (September 22, 2006)
Added f_rename().
Changed option _FS_MINIMUM to _FS_MINIMIZE. R0.02a (June 10, 2006)
Added a configuration option (_FS_MINIMUM).
R0.03a (December 11, 2006)
Improved cluster scan algorithm to write files fast.
Fixed f_mkdir() creates incorrect directory on FAT32.
R0.03 (September 22, 2006)
R0.04 (February 04, 2007) Added f_rename().
Added f_mkfs(). Changed option _FS_MINIMUM to _FS_MINIMIZE.
Supported multiple drive system.
Changed some interfaces for multiple drive system.
Changed f_mountdrv() to f_mount().
R0.03a (December 11, 2006)
R0.04a (April 01, 2007) Improved cluster scan algorithm to write files fast.
Supported multiple partitions on a physical drive. Fixed f_mkdir() creates incorrect directory on FAT32.
Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.04 (February 04, 2007)
R0.04b (May 05, 2007) Added f_mkfs().
Added a configuration option _USE_NTFLAG. Supported multiple drive system.
Added FSINFO support. Changed some interfaces for multiple drive system.
Fixed DBCS name can result FR_INVALID_NAME. Changed f_mountdrv() to f_mount().
Fixed short seek (<= csize) collapses the file object.
R0.05 (August 25, 2007) R0.04a (April 01, 2007)
Changed arguments of f_read(), f_write() and f_mkfs().
Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Supported multiple partitions on a physical drive.
Fixed f_mkdir() on FAT32 creates incorrect directory. Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated. R0.04b (May 05, 2007)
Fixed cached sector is not flushed when create and close without write.
Added a configuration option _USE_NTFLAG.
Added FSINFO support.
R0.06 (April 01, 2008) Fixed DBCS name can result FR_INVALID_NAME.
Added fputc(), fputs(), fprintf() and fgets(). Fixed short seek (<= csize) collapses the file object.
Improved performance of f_lseek() on moving to the same or following cluster.
R0.07 (April 01, 2009) R0.05 (August 25, 2007)
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Added long file name feature. (_USE_LFN) Changed arguments of f_read(), f_write() and f_mkfs().
Added multiple code page feature. (_CODE_PAGE) Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
Added re-entrancy for multitask operation. (_FS_REENTRANT) Fixed f_mkdir() on FAT32 creates incorrect directory.
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision. R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
R0.07a (April 14, 2009) Fixed off by one error at FAT sub-type determination.
Septemberarated out OS dependent code on reentrant cfg. Fixed btr in f_read() can be mistruncated.
Added multiple sector size feature. Fixed cached sector is not flushed when create and close without write.
R0.07c (June 21, 2009)
Fixed f_unlink() can return FR_OK on error. R0.06 (April 01, 2008)
Fixed wrong cache control in f_lseek().
Added relative path feature. Added fputc(), fputs(), fprintf() and fgets().
Added f_chdir() and f_chdrive(). Improved performance of f_lseek() on moving to the same or following cluster.
Added proper case conversion to extended character.
R0.07e (November 03, 2009) R0.07 (April 01, 2009)
Septemberarated out configuration options from ff.h to ffconf.h.
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Fixed name matching error on the 13 character boundary. Added long file name feature. (_USE_LFN)
Added a configuration option, _LFN_UNICODE. Added multiple code page feature. (_CODE_PAGE)
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. Added re-entrancy for multitask operation. (_FS_REENTRANT)
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
R0.08 (May 15, 2010) Changed result code of critical errors.
Added a memory configuration option. (_USE_LFN = 3) Renamed string functions to avoid name collision.
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed .fname in the FILINFO structure on Unicode cfg. R0.07a (April 14, 2009)
String functions support UTF-8 encoding files on Unicode cfg.
Septemberarated out OS dependent code on reentrant cfg.
Added multiple sector size feature.
R0.08a (August 16, 2010)
Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss. R0.07c (June 21, 2009)
Fixed f_mkfs() creates wrong FAT32 volume.
Fixed f_unlink() can return FR_OK on error.
Fixed wrong cache control in f_lseek().
R0.08b (January 15, 2011) Added relative path feature.
Fast seek feature is also applied to f_read() and f_write(). Added f_chdir() and f_chdrive().
f_lseek() reports required table size on creating CLMP. Added proper case conversion to extended character.
Extended format syntax of f_printf().
Ignores duplicated directory separators in given path name.
R0.07e (November 03, 2009)
R0.09 (September 06, 2011)
f_mkfs() supports multiple partition to complete the multiple partition feature. Septemberarated out configuration options from ff.h to ffconf.h.
Added f_fdisk(). Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
Fixed name matching error on the 13 character boundary.
Added a configuration option, _LFN_UNICODE.
R0.09a (August 27, 2012) Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.08 (May 15, 2010)
R0.09b (January 24, 2013) Added a memory configuration option. (_USE_LFN = 3)
Added f_setlabel() and f_getlabel(). Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
R0.10 (October 02, 2013) Changed .fname in the FILINFO structure on Unicode cfg.
Added selection of character encoding on the file. (_STRF_ENCODE) String functions support UTF-8 encoding files on Unicode cfg.
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection. R0.08a (August 16, 2010)
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). Added f_getcwd(). (_FS_RPATH = 2)
Fixed f_write() can be truncated when the file size is close to 4GB. Added sector erase feature. (_USE_ERASE)
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. Moved file lock semaphore table from fs object to the bss.
Fixed f_mkfs() creates wrong FAT32 volume.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS) R0.08b (January 15, 2011)
2nd argument of f_rename() can have a drive number and it will be ignored.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) Fast seek feature is also applied to f_read() and f_write().
Fixed f_close() invalidates the file object without volume lock. f_lseek() reports required table size on creating CLMP.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) Extended format syntax of f_printf().
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) Ignores duplicated directory separators in given path name.
R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry. R0.09 (September 06, 2011)
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
f_mkfs() supports multiple partition to complete the multiple partition feature.
Added f_fdisk().
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
Changed option name _USE_ERASE to _USE_TRIM.
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) R0.09a (August 27, 2012)
Fixed a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.11 (February 09, 2015)
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) R0.09b (January 24, 2013)
Added f_setlabel() and f_getlabel().
R0.10 (October 02, 2013)
Added selection of character encoding on the file. (_STRF_ENCODE)
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection.
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
Fixed f_write() can be truncated when the file size is close to 4GB.
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS)
2nd argument of f_rename() can have a drive number and it will be ignored.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
Fixed f_close() invalidates the file object without volume lock.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry.
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
Changed option name _USE_ERASE to _USE_TRIM.
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
Fixed a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
R0.11 (February 09, 2015)
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
R0.11a (September 05, 2015)
Fixed wrong media change can lead a deadlock at thread-safe configuration.
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
Fixed errors in the case conversion teble of Unicode (cc*.c).
R0.12 (April 12, 2016)
Added support for exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD.
Removed an option _WORD_ACCESS.
Fixed errors in the case conversion table of Unicode (cc*.c).
R0.12a (July 10, 2016)
Added support for creating exFAT volume with some changes of f_mkfs().
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
f_forward() is available regardless of _FS_TINY.
Fixed f_mkfs() creates wrong volume.
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
Fixed wrong memory read in create_name().

42
source/fatfs/00readme.txt Normal file → Executable file
View File

@@ -1,21 +1,21 @@
FatFs Module Source Files R0.11 FatFs Module Source Files R0.12a
FILES FILES
00readme.txt This file. 00readme.txt This file.
history.txt Revision history. history.txt Revision history.
ffconf.h Configuration file for FatFs module. ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module. ff.h Common include file for FatFs and application module.
ff.c FatFs module. ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module. diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs. diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs. integer.h Integer type definitions for FatFs.
option Optional external functions. option Optional external functions.
Low level disk I/O module is not included in this archive because the FatFs Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and not depend on any specific module is only a generic file system layer and not depend on any specific
storage device. You have to provide a low level disk I/O module that written storage device. You have to provide a low level disk I/O module that written
to control the target storage device. to control the target storage device.

View File

@@ -9,7 +9,11 @@
#include "diskio.h" /* FatFs lower layer API */ #include "diskio.h" /* FatFs lower layer API */
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
#include "../crypto.h"
/* Definitions of physical drive number for each media */
#define SDCARD 0
#define CTRNAND 1
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
@@ -30,11 +34,19 @@ DSTATUS disk_status (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize ( DSTATUS disk_initialize (
__attribute__((unused))
BYTE pdrv /* Physical drive nmuber to identify the drive */ BYTE pdrv /* Physical drive nmuber to identify the drive */
) )
{ {
sdmmc_sdcard_init(); switch(pdrv)
{
case SDCARD:
sdmmc_sdcard_init();
break;
case CTRNAND:
ctrNandInit();
break;
}
return RES_OK; return RES_OK;
} }
@@ -45,18 +57,25 @@ DSTATUS disk_initialize (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DRESULT disk_read ( DRESULT disk_read (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */ BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */ DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) )
{ {
if (sdmmc_sdcard_readsectors(sector, count, buff)) { switch(pdrv)
return RES_PARERR; {
} case SDCARD:
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
case CTRNAND:
if(ctrNandRead(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
}
return RES_OK; return RES_OK;
} }
@@ -67,18 +86,16 @@ DRESULT disk_read (
#if _USE_WRITE #if _USE_WRITE
DRESULT disk_write ( DRESULT disk_write (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */ const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */ DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
}
return RES_OK; return RES_OK;
} }
#endif #endif

10731
source/fatfs/ff.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

716
source/fatfs/ff.h Normal file → Executable file
View File

@@ -1,350 +1,366 @@
/*---------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - Generic FAT file system module R0.12a /
/----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of /
/ following conditions. / Copyright (C) 2016, ChaN, all right reserved.
/ /
/ Copyright (C) 2015, ChaN, all right reserved. / FatFs module is an open source software. Redistribution and use of FatFs in
/ / source and binary forms, with or without modification, are permitted provided
/ 1. Redistributions of source code must retain the above copyright notice, / that the following condition is met:
/ this condition and the following disclaimer.
/ / 1. Redistributions of source code must retain the above copyright notice,
/ This software is provided by the copyright holder and contributors "AS IS" / this condition and the following disclaimer.
/ and any warranties related to this software are DISCLAIMED. /
/ The copyright owner or contributors be NOT LIABLE for any damages caused / This software is provided by the copyright holder and contributors "AS IS"
/ by use of this software. / and any warranties related to this software are DISCLAIMED.
/---------------------------------------------------------------------------*/ / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 32020 /* Revision ID */
#ifndef _FATFS
#ifdef __cplusplus #define _FATFS 80186 /* Revision ID */
extern "C" {
#endif #ifdef __cplusplus
extern "C" {
#include "integer.h" /* Basic integer types */ #endif
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #include "integer.h" /* Basic integer types */
#error Wrong configuration file (ffconf.h). #include "ffconf.h" /* FatFs configuration options */
#endif
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct { /* Definitions of volume management */
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ #if _MULTI_PARTITION /* Multiple partition configuration */
} PARTITION; typedef struct {
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ BYTE pd; /* Physical drive number */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ } PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#else /* Single partition configuration */ #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#else /* Single partition configuration */
#endif #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN /* Type of path name strings on FatFs API */
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif #if _LFN_UNICODE /* Unicode (UTF-16) string */
#ifndef _INC_TCHAR #if _USE_LFN == 0
typedef WCHAR TCHAR; #error _LFN_UNICODE must be 0 at non-LFN cfg.
#define _T(x) L ## x #endif
#define _TEXT(x) L ## x #ifndef _INC_TCHAR
#endif typedef WCHAR TCHAR;
#define _T(x) L ## x
#else /* ANSI/OEM string */ #define _TEXT(x) L ## x
#ifndef _INC_TCHAR #endif
typedef char TCHAR; #else /* ANSI/OEM string */
#define _T(x) x #ifndef _INC_TCHAR
#define _TEXT(x) x typedef char TCHAR;
#endif #define _T(x) x
#define _TEXT(x) x
#endif #endif
#endif
/* File system object structure (FATFS) */
/* Type of file size variables */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */ #if _FS_EXFAT
BYTE drv; /* Physical drive number */ #if _USE_LFN == 0
BYTE csize; /* Sectors per cluster (1,2,4...128) */ #error LFN must be enabled when enable exFAT
BYTE n_fats; /* Number of FAT copies (1 or 2) */ #endif
BYTE wflag; /* win[] flag (b0:dirty) */ typedef QWORD FSIZE_t;
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ #else
WORD id; /* File system mount ID */ typedef DWORD FSIZE_t;
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ #endif
#if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT /* File system object structure (FATFS) */
_SYNC_t sobj; /* Identifier of sync object */
#endif typedef struct {
#if !_FS_READONLY BYTE fs_type; /* File system type (0:N/A) */
DWORD last_clust; /* Last allocated cluster */ BYTE drv; /* Physical drive number */
DWORD free_clust; /* Number of free clusters */ BYTE n_fats; /* Number of FATs (1 or 2) */
#endif BYTE wflag; /* win[] flag (b0:dirty) */
#if _FS_RPATH BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
DWORD cdir; /* Current directory start cluster (0:root) */ WORD id; /* File system mount ID */
#endif WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ WORD csize; /* Cluster size [sectors] */
DWORD fsize; /* Sectors per FAT */ #if _MAX_SS != _MIN_SS
DWORD volbase; /* Volume start sector */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
DWORD fatbase; /* FAT start sector */ #endif
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ #if _USE_LFN != 0
DWORD database; /* Data start sector */ WCHAR* lfnbuf; /* LFN working buffer */
DWORD winsect; /* Current sector appearing in the win[] */ #endif
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ #if _FS_EXFAT
} FATFS; BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
/* File object structure (FIL) */ #endif
#if !_FS_READONLY
typedef struct { DWORD last_clst; /* Last allocated cluster */
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ DWORD free_clst; /* Number of free clusters */
WORD id; /* Owner file system mount ID (**do not change order**) */ #endif
BYTE flag; /* Status flags */ #if _FS_RPATH != 0
BYTE err; /* Abort flag (error code) */ DWORD cdir; /* Current directory start cluster (0:root) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */ #if _FS_EXFAT
DWORD fsize; /* File size */ DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ #endif
#if !_FS_READONLY #endif
DWORD dir_sect; /* Sector number containing the directory entry */ DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ DWORD fsize; /* Size of an FAT [sectors] */
#endif DWORD volbase; /* Volume base sector */
#if _USE_FASTSEEK DWORD fatbase; /* FAT base sector */
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ DWORD dirbase; /* Root directory base sector/cluster */
#endif DWORD database; /* Data base sector */
#if _FS_LOCK DWORD winsect; /* Current sector appearing in the win[] */
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
#endif } FATFS;
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL; /* Object ID and allocation information (_FDID) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
/* Directory object structure (DIR) */ WORD id; /* Owner file system mount ID */
BYTE attr; /* Object attribute */
typedef struct { BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
WORD id; /* Owner file system mount ID (**do not change order**) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
WORD index; /* Current read/write index number */ #if _FS_EXFAT
DWORD sclust; /* Table start cluster (0:Root dir) */ DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
DWORD clust; /* Current cluster */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD sect; /* Current sector */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */ DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ #endif
#if _FS_LOCK #if _FS_LOCK != 0
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif #endif
#if _USE_LFN } _FDID;
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
#if _USE_FIND /* File object structure (FIL) */
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif typedef struct {
} DIR; _FDID obj; /* Object identifier */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
/* File information structure (FILINFO) */ DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
typedef struct { #if !_FS_READONLY
DWORD fsize; /* File size */ DWORD dir_sect; /* Sector number containing the directory entry */
WORD fdate; /* Last modified date */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
WORD ftime; /* Last modified time */ #endif
BYTE fattrib; /* Attribute */ #if _USE_FASTSEEK
TCHAR fname[13]; /* Short file name (8.3 format) */ DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#if _USE_LFN #endif
TCHAR* lfname; /* Pointer to the LFN buffer */ #if !_FS_TINY
UINT lfsize; /* Size of LFN buffer in TCHAR */ BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif #endif
} FILINFO; } FIL;
/* File function return code (FRESULT) */ /* Directory object structure (DIR) */
typedef enum { typedef struct {
FR_OK = 0, /* (0) Succeeded */ _FDID obj; /* Object identifier */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ DWORD dptr; /* Current read/write offset */
FR_INT_ERR, /* (2) Assertion failed */ DWORD clust; /* Current cluster */
FR_NOT_READY, /* (3) The physical drive cannot work */ DWORD sect; /* Current sector */
FR_NO_FILE, /* (4) Could not find the file */ BYTE* dir; /* Pointer to the directory item in the win[] */
FR_NO_PATH, /* (5) Could not find the path */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
FR_INVALID_NAME, /* (6) The path name format is invalid */ #if _USE_LFN != 0
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
FR_EXIST, /* (8) Access denied due to prohibited access */ #endif
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ #if _USE_FIND
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ const TCHAR* pat; /* Pointer to the name matching pattern */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ #endif
FR_NOT_ENABLED, /* (12) The volume has no work area */ } DIR;
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ /* File information structure (FILINFO) */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ typedef struct {
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FSIZE_t fsize; /* File size */
} FRESULT; WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */
#if _USE_LFN != 0
/*--------------------------------------------------------------*/ TCHAR altname[13]; /* Altenative file name */
/* FatFs module application interface */ TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
#else
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ TCHAR fname[13]; /* File name */
FRESULT f_close (FIL* fp); /* Close an open file object */ #endif
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ } FILINFO;
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */ /* File function return code (FRESULT) */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ typedef enum {
FRESULT f_closedir (DIR* dp); /* Close an open directory */ FR_OK = 0, /* (0) Succeeded */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FR_INT_ERR, /* (2) Assertion failed */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FR_NOT_READY, /* (3) The physical drive cannot work */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FR_NO_FILE, /* (4) Could not find the file */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FR_NO_PATH, /* (5) Could not find the path */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FR_INVALID_NAME, /* (6) The path name format is invalid */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ FR_EXIST, /* (8) Access denied due to prohibited access */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FR_NOT_ENABLED, /* (12) The volume has no work area */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ } FRESULT;
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) /*--------------------------------------------------------------*/
#define f_error(fp) ((fp)->err) /* FatFs module application interface */
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize) FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
#define f_rewind(fp) f_lseek((fp), 0) FRESULT f_close (FIL* fp); /* Close an open file object */
#define f_rewinddir(dp) f_readdir((dp), 0) FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
#ifndef EOF FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
#define EOF (-1) FRESULT f_truncate (FIL* fp); /* Truncate the file */
#endif FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
/*--------------------------------------------------------------*/ FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
/* Additional user defined functions */ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
/* RTC function */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
#if !_FS_READONLY && !_FS_NORTC FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
DWORD get_fattime (void); FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
#endif FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
/* Unicode support functions */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
#if _USE_LFN /* Unicode - OEM code conversion */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
#if _USE_LFN == 3 /* Memory functions */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
void* ff_memalloc (UINT msize); /* Allocate memory block */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
void ff_memfree (void* mblock); /* Free memory block */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
#endif FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
#endif FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
/* Sync functions */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
#if _FS_REENTRANT int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#endif #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
/*--------------------------------------------------------------*/
/* Flags and offset address */ #ifndef EOF
#define EOF (-1)
#endif
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
/*--------------------------------------------------------------*/
#if !_FS_READONLY /* Additional user defined functions */
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04 /* RTC function */
#define FA_CREATE_ALWAYS 0x08 #if !_FS_READONLY && !_FS_NORTC
#define FA_OPEN_ALWAYS 0x10 DWORD get_fattime (void);
#define FA__WRITTEN 0x20 #endif
#define FA__DIRTY 0x40
#endif /* Unicode support functions */
#if _USE_LFN != 0 /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
/* FAT sub type (FATFS.fs_type) */ WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
#define FS_FAT12 1 void* ff_memalloc (UINT msize); /* Allocate memory block */
#define FS_FAT16 2 void ff_memfree (void* mblock); /* Free memory block */
#define FS_FAT32 3 #endif
#endif
/* File attribute bits for directory entry */ /* Sync functions */
#if _FS_REENTRANT
#define AM_RDO 0x01 /* Read only */ int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
#define AM_HID 0x02 /* Hidden */ int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
#define AM_SYS 0x04 /* System */ void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
#define AM_VOL 0x08 /* Volume label */ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#define AM_LFN 0x0F /* LFN entry */ #endif
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/*--------------------------------------------------------------*/
/* Fast seek feature */ /* Flags and offset address */
#define CREATE_LINKMAP 0xFFFFFFFF
/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
/*--------------------------------*/ #define FA_WRITE 0x02
/* Multi-byte word access macros */ #define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ #define FA_CREATE_ALWAYS 0x08
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) #define FA_OPEN_ALWAYS 0x10
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) #define FA_OPEN_APPEND 0x30
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) /* Fast seek controls (2nd argument of f_lseek) */
#else /* Use byte-by-byte access to the FAT structure */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) /* Format options (2nd argument of f_mkfs) */
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) #define FM_FAT 0x01
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) #define FM_FAT32 0x02
#endif #define FM_EXFAT 0x04
#define FM_ANY 0x07
#ifdef __cplusplus #define FM_SFD 0x08
}
#endif /* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#endif /* _FATFS */ #define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

536
source/fatfs/ffconf.h Normal file → Executable file
View File

@@ -1,271 +1,265 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 80186 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0 #define _FS_READONLY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ bytes. Instead of private sector buffer eliminated from the file object, / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ common sector buffer in the file system object (FATFS) is used for the file / and optional writing functions as well. */
/ data transfer. */
#define _FS_MINIMIZE 0
#define _FS_READONLY 0 /* This option defines minimization level to remove some basic API functions.
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / 0: All basic functions are enabled.
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ and optional writing functions as well. */ / are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/ #define _USE_STRFUNC 0
/ 0: All basic functions are enabled. /* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), / f_printf().
/ f_truncate() and f_rename() function are removed. /
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 0: Disable string functions.
/ 3: f_lseek() function is removed in addition to 2. */ / 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and #define _USE_FIND 1
/ f_printf(). /* This option switches filtered directory read functions, f_findfirst() and
/ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */ #define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FIND 0
/* This option switches filtered directory read feature and related functions, #define _USE_FASTSEEK 0
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
#define _USE_MKFS 0 #define _USE_EXPAND 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_expand function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 0 #define _USE_CHMOD 0
/* This option switches fast seek feature. (0:Disable or 1:Enable) */ /* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel(). #define _USE_LABEL 0
/ (0:Disable or 1:Enable) */ /* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) #define _USE_FORWARD 0
/ To enable it, also _FS_TINY need to be set to 1. */ /* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _CODE_PAGE 437 #define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system. /* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure. / Incorrect setting of the code page can cause a file open failure.
/ /
/ 1 - ASCII (No extended character. Non-LFN cfg. only) / 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S. / 437 - U.S.
/ 720 - Arabic / 720 - Arabic
/ 737 - Greek / 737 - Greek
/ 775 - Baltic / 771 - KBL
/ 850 - Multilingual Latin 1 / 775 - Baltic
/ 852 - Latin 2 / 850 - Latin 1
/ 855 - Cyrillic / 852 - Latin 2
/ 857 - Turkish / 855 - Cyrillic
/ 858 - Multilingual Latin 1 + Euro / 857 - Turkish
/ 862 - Hebrew / 860 - Portuguese
/ 866 - Russian / 861 - Icelandic
/ 874 - Thai / 862 - Hebrew
/ 932 - Japanese Shift_JIS (DBCS) / 863 - Canadian French
/ 936 - Simplified Chinese GBK (DBCS) / 864 - Arabic
/ 949 - Korean (DBCS) / 865 - Nordic
/ 950 - Traditional Chinese Big5 (DBCS) / 866 - Russian
*/ / 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
#define _USE_LFN 2 / 949 - Korean (DBCS)
#define _MAX_LFN 255 / 950 - Traditional Chinese (DBCS)
/* The _USE_LFN option switches the LFN feature. */
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. #define _USE_LFN 2
/ 2: Enable LFN with dynamic working buffer on the STACK. #define _MAX_LFN 255
/ 3: Enable LFN with dynamic working buffer on the HEAP. /* The _USE_LFN switches the support of long file name (LFN).
/ /
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must / 0: Disable support of LFN. _MAX_LFN has no effect.
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ When use stack for the working buffer, take care on stack overflow. When use heap / 2: Enable LFN with dynamic working buffer on the STACK.
/ memory for the working buffer, memory management functions, ff_memalloc() and / 3: Enable LFN with dynamic working buffer on the HEAP.
/ ff_memfree(), must be added to the project. */ /
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
#define _LFN_UNICODE 0 / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) / It should be set 255 to support full featured LFN operations.
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE / When use stack for the working buffer, take care on stack overflow. When use heap
/ to 1. This option also affects behavior of string I/O functions. */ / memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _STRF_ENCODE 0
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to #define _LFN_UNICODE 0
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
/ / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ 0: ANSI/OEM / This option also affects behavior of string I/O functions. */
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8 #define _STRF_ENCODE 3
/ /* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
/ When _LFN_UNICODE is 0, this option has no effect. */ / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
/ 0: ANSI/OEM
#define _FS_RPATH 0 / 1: UTF-16LE
/* This option configures relative path feature. / 2: UTF-16BE
/ / 3: UTF-8
/ 0: Disable relative path feature and remove related functions. /
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. / This option has no effect when _LFN_UNICODE == 0. */
/ 2: f_getcwd() function is available in addition to 1.
/
/ Note that directory items read via f_readdir() are affected by this option. */ #define _FS_RPATH 0
/* This option configures support of relative path.
/
/*---------------------------------------------------------------------------/ / 0: Disable relative path and remove related functions.
/ Drive/Volume Configurations / 1: Enable relative path. f_chdir() and f_chdrive() are available.
/---------------------------------------------------------------------------*/ / 2: f_getcwd() function is available in addition to 1.
*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
#define _STR_VOLUME_ID 0 /---------------------------------------------------------------------------*/
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
/* _STR_VOLUME_ID option switches string volume ID feature. #define _VOLUMES 2
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive /* Number of volumes (logical drives) to be used. */
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */ #define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID.
#define _MULTI_PARTITION 0 / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/* This option switches multi-partition feature. By default (0), each logical drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ number is bound to the same physical drive number and only an FAT volume found on / logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the physical drive will be mounted. When multi-partition feature is enabled (1), / the drive ID strings are: A-Z and 0-9. */
/ each logical drive number is bound to arbitrary physical drive and partition
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MULTI_PARTITION 0
/* This option switches support of multi-partition on a physical drive.
#define _MIN_SS 512 / By default (0), each logical drive number is bound to the same physical drive
#define _MAX_SS 512 / number and only an FAT volume found on the physical drive will be mounted.
/* These options configure the range of sector size to be supported. (512, 1024, / When multi-partition is enabled (1), each logical drive number can be bound to
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ harddisk. But a larger value may be required for on-board flash memory and some / funciton will be available. */
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */ #define _MIN_SS 512
#define _MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024,
#define _USE_TRIM 0 / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) / harddisk. But a larger value may be required for on-board flash memory and some
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ disk_ioctl() function. */ / to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this #define _USE_TRIM 0
/ option, and f_getfree() function at first time after volume mount will force /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. / To enable Trim function, also CTRL_TRIM command should be implemented to the
/ / disk_ioctl() function. */
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available. #define _FS_NOFSINFO 0
/ bit1=1: Do not trust last allocated cluster number in the FSINFO. /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
*/ / option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/*---------------------------------------------------------------------------/ / bit0=1: Do not trust free cluster count in the FSINFO.
/ System Configurations / bit1=0: Use last allocated cluster number in the FSINFO if available.
/---------------------------------------------------------------------------*/ / bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
#define _FS_NORTC 1
#define _NORTC_MON 2
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015 /*---------------------------------------------------------------------------/
/* The _FS_NORTC option switches timestamp feature. If the system does not have / System Configurations
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable /---------------------------------------------------------------------------*/
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. #define _FS_TINY 0
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ to be added to the project to read current time form RTC. _NORTC_MON, / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
/ _NORTC_MDAY and _NORTC_YEAR have no effect. / Instead of private sector buffer eliminated from the file object, common sector
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ / buffer in the file system object (FATFS) is used for the file data transfer. */
#define _FS_LOCK 0 #define _FS_EXFAT 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open /* This option switches support of exFAT file system in addition to the traditional
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY / FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
/ is 1. / Note that enabling exFAT discards C89 compatibility. */
/
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects. #define _FS_NORTC 1
/ >0: Enable file lock feature. The value defines how many files/sub-directories #define _NORTC_MON 1
/ can be opened simultaneously under file lock control. Note that the file #define _NORTC_MDAY 1
/ lock feature is independent of re-entrancy. */ #define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
#define _FS_REENTRANT 0 / the timestamp function. All objects modified by FatFs will have a fixed timestamp
#define _FS_TIMEOUT 1000 / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
#define _SYNC_t HANDLE / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs / added to the project to get current time form real-time clock. _NORTC_MON,
/ module itself. Note that regardless of this option, file access to different / _NORTC_MDAY and _NORTC_YEAR have no effect.
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / These options have no effect at read-only configuration (_FS_READONLY = 1). */
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this feature.
/ #define _FS_LOCK 0
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. /* The option _FS_LOCK switches file lock function to control duplicated file open
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / is 1.
/ function, must be added to the project. Samples are available in /
/ option/syscall.c. / 0: Disable file lock function. To avoid volume corruption, application program
/ / should avoid illegal open, remove and rename to the open objects.
/ The _FS_TIMEOUT defines timeout period in unit of time tick. / >0: Enable file lock function. The value defines how many files/sub-directories
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / can be opened simultaneously under file lock control. Note that the file
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be / lock control is independent of re-entrancy. */
/ included somewhere in the scope of ff.c. */
#define _FS_REENTRANT 0
#define _WORD_ACCESS 0 #define _FS_TIMEOUT 1000
/* The _WORD_ACCESS option is an only platform dependent option. It defines #define _SYNC_t HANDLE
/ which access method is used to the word data on the FAT volume. /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ / module itself. Note that regardless of this option, file access to different
/ 0: Byte-by-byte access. Always compatible with all platforms. / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ 1: Word access. Do not choose this unless under both the following conditions. / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ / to the same volume is under control of this function.
/ * Address misaligned memory access is always allowed to ALL instructions. /
/ * Byte order on the memory is little-endian. / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ Following table shows allowable settings of some processor types. / function, must be added to the project. Samples are available in
/ / option/syscall.c.
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 /
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 / The _FS_TIMEOUT defines timeout period in unit of time tick.
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 / included somewhere in the scope of ff.c. */
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1 /*--- End of configuration options ---*/
/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

71
source/fatfs/integer.h Normal file → Executable file
View File

@@ -1,33 +1,38 @@
/*-------------------------------------------*/ /*-------------------------------------------*/
/* Integer type definitions for FatFs module */ /* Integer type definitions for FatFs module */
/*-------------------------------------------*/ /*-------------------------------------------*/
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* FatFs development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* This type MUST be 8 bit */ #else /* Embedded platform */
typedef unsigned char BYTE;
/* These types MUST be 16-bit or 32-bit */
/* These types MUST be 16 bit */ typedef int INT;
typedef short SHORT; typedef unsigned int UINT;
typedef unsigned short WORD;
typedef unsigned short WCHAR; /* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16 bit or 32 bit */
typedef int INT; /* These types MUST be 16-bit */
typedef unsigned int UINT; typedef short SHORT;
typedef unsigned short WORD;
/* These types MUST be 32 bit */ typedef unsigned short WCHAR;
typedef long LONG;
typedef unsigned long DWORD; /* These types MUST be 32-bit */
typedef long LONG;
#endif typedef unsigned long DWORD;
#endif /* This type MUST be 64-bit (Remove this for C89 compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

388
source/fatfs/option/ccsbcs.c Executable file
View File

@@ -0,0 +1,388 @@
/*------------------------------------------------------------------------*/
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
/* (SBCS code pages) */
/*------------------------------------------------------------------------*/
/* 437 U.S.
/ 720 Arabic
/ 737 Greek
/ 771 KBL
/ 775 Baltic
/ 850 Latin 1
/ 852 Latin 2
/ 855 Cyrillic
/ 857 Turkish
/ 860 Portuguese
/ 861 Icelandic
/ 862 Hebrew
/ 863 Canadian French
/ 864 Arabic
/ 865 Nordic
/ 866 Russian
/ 869 Greek 2
*/
#include "../ff.h"
#if _CODE_PAGE == 437
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 720
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 737
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 771
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 775
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 850
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 852
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 855
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 857
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 860
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 861
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 862
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 863
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 864
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
};
#elif _CODE_PAGE == 865
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 866
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 869
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
};
#endif
#if !_TBLDEF || !_USE_LFN
#error This file is not needed at current configuration. Remove from the project.
#endif
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
WCHAR c;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to Unicode */
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
} else { /* Unicode to OEM code */
for (c = 0; c < 0x80; c++) {
if (chr == Tbl[c]) break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper ( /* Returns upper converted character */
WCHAR chr /* Unicode character to be upper converted (BMP only) */
)
{
/* Compressed upper conversion table */
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */
/* Basic Latin */
0x0061,0x031A,
/* Latin-1 Supplement */
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
/* Latin Extended-A */
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
/* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
/* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
/* Armenian */
0x0561,0x0426,
0x0000
};
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */
/* Phonetic Extensions */
0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */
0x1E00,0x0196, 0x1EA0,0x015A,
/* Greek Extended */
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC,
/* Letterlike Symbols */
0x214E,0x0001,0x2132,
/* Number forms */
0x2170,0x0210, 0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */
0x24D0,0x051A, 0x2C30,0x042F,
/* Latin Extended-C */
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */
0x2C80,0x0164,
/* Georgian Supplement */
0x2D00,0x0826,
/* Full-width */
0xFF41,0x031A,
0x0000
};
const WCHAR *p;
WCHAR bc, nc, cmd;
p = chr < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get block base */
if (!bc || chr < bc) break;
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (chr < bc + nc) { /* In the block? */
switch (cmd) {
case 0: chr = p[chr - bc]; break; /* Table conversion */
case 1: chr -= (chr - bc) & 1; break; /* Case pairs */
case 2: chr -= 16; break; /* Shift -16 */
case 3: chr -= 32; break; /* Shift -32 */
case 4: chr -= 48; break; /* Shift -48 */
case 5: chr -= 26; break; /* Shift -26 */
case 6: chr += 8; break; /* Shift +8 */
case 7: chr -= 80; break; /* Shift -80 */
case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */
}
break;
}
if (!cmd) p += nc;
}
return chr;
}

View File

@@ -1,151 +0,0 @@
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2014 */
/*------------------------------------------------------------------------*/
#include "../ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
BYTE vol, /* Corresponding logical drive being processed */
_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
int ret;
*sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
ret = (int)(*sobj != INVALID_HANDLE_VALUE);
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
// ret = 1; /* The initial value of the semaphore must be 1. */
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
// ret = (int)(*sobj != NULL);
return ret;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
int ret;
ret = CloseHandle(sobj); /* Win32 */
// ret = 1; /* uITRON (nothing to do) */
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// vSemaphoreDelete(sobj); /* FreeRTOS */
// ret = 1;
return ret;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
_SYNC_t sobj /* Sync object to wait */
)
{
int ret;
ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
return ret;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
_SYNC_t sobj /* Sync object to be signaled */
)
{
ReleaseMutex(sobj); /* Win32 */
// sig_sem(sobj); /* uITRON */
// OSMutexPost(sobj); /* uC/OS-II */
// xSemaphoreGive(sobj); /* FreeRTOS */
}
#endif
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free */
)
{
free(mblock); /* Discard the memory block with POSIX API */
}
#endif

View File

@@ -1,15 +1,4 @@
#pragma once #pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include "../../types.h"
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define vu8 volatile u8
#define vu16 volatile u16
#define vu32 volatile u32
#define vu64 volatile u64

View File

@@ -1,15 +1,17 @@
.arm // Copyright 2014 Normmatt
.global waitcycles // Licensed under GPLv2 or any later version
.type waitcycles STT_FUNC // Refer to the license.txt file included.
@waitcycles ( u32 us ) .arm
waitcycles: .global ioDelay
PUSH {R0-R2,LR} .type ioDelay STT_FUNC
STR R0, [SP,#4]
waitcycles_loop: @ioDelay ( u32 us )
LDR R3, [SP,#4] ioDelay:
SUBS R2, R3, #1 ldr r1, =0x18000000 @ VRAM
STR R2, [SP,#4] 1:
CMP R3, #0 @ Loop doing uncached reads from VRAM to make loop timing more reliable
BNE waitcycles_loop ldr r2, [r1]
POP {R0-R2,PC} subs r0, #1
bgt 1b
bx lr

View File

@@ -1,616 +1,429 @@
/* // Copyright 2014 Normmatt
* This Source Code Form is subject to the terms of the Mozilla Public // Licensed under GPLv2 or any later version
* License, v. 2.0. If a copy of the MPL was not distributed with this file, // Refer to the license.txt file included.
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2014, Normmatt
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 2, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include "sdmmc.h" #include "sdmmc.h"
//#include "DrawCharacter.h" #include "delay.h"
//Uncomment to enable 32bit fifo support? struct mmcdevice handleNAND;
//not currently working struct mmcdevice handleSD;
#define DATA32_SUPPORT
#define TRUE 1 static inline u16 sdmmc_read16(u16 reg) {
#define FALSE 0 return *(vu16*)(SDMMC_BASE + reg);
}
#define bool int static inline void sdmmc_write16(u16 reg, u16 val) {
*(vu16*)(SDMMC_BASE + reg) = val;
}
#define NO_INLINE __attribute__ ((noinline)) static inline u32 sdmmc_read32(u16 reg) {
return *(vu32*)(SDMMC_BASE + reg);
}
#define RGB(r,g,b) (r<<24|b<<16|g<<8|r) static inline void sdmmc_write32(u16 reg, u32 val) {
*(vu32*)(SDMMC_BASE + reg) = val;
}
#ifdef __cplusplus static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
extern "C" { u16 val = sdmmc_read16(reg);
#endif val &= ~clear;
void waitcycles(uint32_t val); val |= set;
#ifdef __cplusplus sdmmc_write16(reg, val);
}; }
#endif
//#define DEBUG_SDMMC static inline void setckl(u32 data)
{
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
}
#ifdef DEBUG_SDMMC
extern uint8_t* topScreen;
extern void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor);
#define DEBUGPRINT(scr,str,hex,x,y,color,bg) DrawHexWithName(scr,str,hex,x,y,color,bg)
#else
#define DEBUGPRINT(...)
#endif
//extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args);
//extern "C" void inittarget(struct mmcdevice *ctx);
//extern "C" int SD_Init();
//extern "C" int SD_Init2();
//extern "C" int Nand_Init2();
//extern "C" void InitSD();
struct mmcdevice handelNAND;
struct mmcdevice handelSD;
mmcdevice *getMMCDevice(int drive) mmcdevice *getMMCDevice(int drive)
{ {
if(drive==0) return &handelNAND; if(drive==0) return &handleNAND;
return &handelSD; return &handleSD;
} }
int geterror(struct mmcdevice *ctx) static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx)
{ {
return (ctx->error << 29) >> 31; return (ctx->error << 29) >> 31;
} }
static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
void inittarget(struct mmcdevice *ctx)
{ {
sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber); sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
setckl(ctx->clk); setckl(ctx->clk);
if(ctx->SDOPT == 0) if (ctx->SDOPT == 0) {
{ sdmmc_mask16(REG_SDOPT, 0, 0x8000);
sdmmc_mask16(REG_SDOPT,0,0x8000); } else {
} sdmmc_mask16(REG_SDOPT, 0x8000, 0);
else }
{
sdmmc_mask16(REG_SDOPT,0x8000,0);
}
} }
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args)
{ {
bool getSDRESP = (cmd << 15) >> 31; bool getSDRESP = (cmd << 15) >> 31;
uint16_t flags = (cmd << 15) >> 31; u16 flags = (cmd << 15) >> 31;
const bool readdata = cmd & 0x20000; const bool readdata = cmd & 0x20000;
const bool writedata = cmd & 0x40000; const bool writedata = cmd & 0x40000;
if(readdata || writedata) if (readdata || writedata)
{ flags |= TMIO_STAT0_DATAEND;
flags |= TMIO_STAT0_DATAEND;
} ctx->error = 0;
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
ctx->error = 0; sdmmc_write16(REG_SDIRMASK0,0);
while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? sdmmc_write16(REG_SDIRMASK1,0);
sdmmc_write16(REG_SDIRMASK0,0); sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDIRMASK1,0); sdmmc_write16(REG_SDSTATUS1,0);
sdmmc_write16(REG_SDSTATUS0,0); sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
sdmmc_write16(REG_SDSTATUS1,0);
#ifdef DATA32_SUPPORT sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
// if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800); sdmmc_write16(REG_SDCMDARG1,args >> 16);
// if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000); sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
// sdmmc_mask16(REG_DATACTL32,0x1800,2);
#else u32 size = ctx->size;
sdmmc_mask16(REG_DATACTL32,0x1800,0); vu8 *dataPtr = ctx->data;
#endif
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); bool useBuf = ( NULL != dataPtr );
sdmmc_write16(REG_SDCMDARG1,args >> 16);
sdmmc_write16(REG_SDCMD,cmd &0xFFFF); u16 status0 = 0;
while(true) {
uint32_t size = ctx->size; u16 status1 = sdmmc_read16(REG_SDSTATUS1);
uint16_t *dataPtr = (uint16_t*)ctx->data; if (status1 & TMIO_STAT1_RXRDY) {
uint32_t *dataPtr32 = (uint32_t*)ctx->data; if (readdata && useBuf) {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
bool useBuf = ( NULL != dataPtr ); //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr)))); if (size > 0x1FF) {
for(int i = 0; i<0x200; i+=2) {
uint16_t status0 = 0; u16 data = sdmmc_read16(REG_SDFIFO);
while(1) *dataPtr++ = data & 0xFF;
{ *dataPtr++ = data >> 8;
volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); }
#ifdef DATA32_SUPPORT size -= 0x200;
volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); }
if((ctl32 & 0x100)) }
#else }
if((status1 & TMIO_STAT1_RXRDY))
#endif if (status1 & TMIO_STAT1_TXRQ) {
{ if (writedata && useBuf) {
if(readdata) sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
{ //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
if(useBuf) if (size > 0x1FF) {
{ for (int i = 0; i<0x200; i+=2) {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); u16 data = *dataPtr++;
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); data |= *dataPtr++ << 8;
if(size > 0x1FF) sdmmc_write16(REG_SDFIFO, data);
{ }
#ifdef DATA32_SUPPORT size -= 0x200;
if(useBuf32) }
{ }
for(int i = 0; i<0x200; i+=4) }
{ if (status1 & TMIO_MASK_GW) {
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32); ctx->error |= 4;
} break;
} }
else
{ if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
#endif status0 = sdmmc_read16(REG_SDSTATUS0);
for(int i = 0; i<0x200; i+=2) if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
{ ctx->error |= 0x1;
*dataPtr++ = sdmmc_read16(REG_SDFIFO); if (status0 & TMIO_STAT0_DATAEND)
} ctx->error |= 0x2;
#ifdef DATA32_SUPPORT
} if ((status0 & flags) == flags)
#endif break;
size -= 0x200; }
} }
} ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
sdmmc_mask16(REG_DATACTL32, 0x800, 0); sdmmc_write16(REG_SDSTATUS0,0);
} sdmmc_write16(REG_SDSTATUS1,0);
}
#ifdef DATA32_SUPPORT if (getSDRESP != 0) {
if(!(ctl32 & 0x200)) ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16);
#else ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16);
if((status1 & TMIO_STAT1_TXRQ)) ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16);
#endif ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16);
{ }
if(writedata)
{
if(useBuf)
{
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
if(size > 0x1FF)
{
#ifdef DATA32_SUPPORT
for(int i = 0; i<0x200; i+=4)
{
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
}
#else
for(int i = 0; i<0x200; i+=2)
{
sdmmc_write16(REG_SDFIFO,*dataPtr++);
}
#endif
size -= 0x200;
}
}
sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
}
}
if(status1 & TMIO_MASK_GW)
{
ctx->error |= 4;
break;
}
if(!(status1 & TMIO_STAT1_CMD_BUSY))
{
status0 = sdmmc_read16(REG_SDSTATUS0);
if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
{
ctx->error |= 0x1;
}
if(status0 & TMIO_STAT0_DATAEND)
{
ctx->error |= 0x2;
}
if((status0 & flags) == flags)
break;
}
}
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1,0);
if(getSDRESP != 0)
{
ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16);
}
} }
int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) u32 __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in)
{ {
if(handelSD.isSDHC == 0) sector_no <<= 9; if (handleSD.isSDHC == 0)
inittarget(&handelSD); sector_no <<= 9;
sdmmc_write16(REG_SDSTOP,0x100); inittarget(&handleSD);
#ifdef DATA32_SUPPORT sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200); sdmmc_write16(REG_SDBLKCOUNT,numsectors);
#endif handleSD.data = in;
sdmmc_write16(REG_SDBLKCOUNT,numsectors); handleSD.size = numsectors << 9;
handelSD.data = in; sdmmc_send_command(&handleSD,0x52C19,sector_no);
handelSD.size = numsectors << 9; return geterror(&handleSD);
sdmmc_send_command(&handelSD,0x52C19,sector_no);
return geterror(&handelSD);
} }
int NO_INLINE sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
{ {
if(handelSD.isSDHC == 0) sector_no <<= 9; if (handleSD.isSDHC == 0)
inittarget(&handelSD); sector_no <<= 9;
sdmmc_write16(REG_SDSTOP,0x100); inittarget(&handleSD);
#ifdef DATA32_SUPPORT sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200); sdmmc_write16(REG_SDBLKCOUNT,numsectors);
#endif handleSD.data = out;
sdmmc_write16(REG_SDBLKCOUNT,numsectors); handleSD.size = numsectors << 9;
handelSD.data = out; sdmmc_send_command(&handleSD,0x33C12,sector_no);
handelSD.size = numsectors << 9; return geterror(&handleSD);
sdmmc_send_command(&handelSD,0x33C12,sector_no);
return geterror(&handelSD);
} }
u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
{ {
if(handelNAND.isSDHC == 0) sector_no <<= 9; if (handleNAND.isSDHC == 0)
inittarget(&handelNAND); sector_no <<= 9;
sdmmc_write16(REG_SDSTOP,0x100); inittarget(&handleNAND);
#ifdef DATA32_SUPPORT sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200); sdmmc_write16(REG_SDBLKCOUNT,numsectors);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors); handleNAND.data = out;
handelNAND.data = out; handleNAND.size = numsectors << 9;
handelNAND.size = numsectors << 9; sdmmc_send_command(&handleNAND,0x33C12,sector_no);
sdmmc_send_command(&handelNAND,0x33C12,sector_no); inittarget(&handleSD);
inittarget(&handelSD); return geterror(&handleNAND);
return geterror(&handelNAND);
} }
int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) //experimental static u32 calcSDSize(u8* csd, int type)
{ {
if(handelNAND.isSDHC == 0) sector_no <<= 9; u32 result = 0;
inittarget(&handelNAND); if (type == -1) type = csd[14] >> 6;
sdmmc_write16(REG_SDSTOP,0x100); switch (type) {
#ifdef DATA32_SUPPORT case 0:
sdmmc_write16(REG_SDBLKCOUNT32,numsectors); {
sdmmc_write16(REG_SDBLKLEN32,0x200); u32 block_len = csd[9] & 0xf;
#endif block_len = 1u << block_len;
sdmmc_write16(REG_SDBLKCOUNT,numsectors); u32 mult = (u32)(csd[4] >> 7) | (u32)((csd[5] & 3) << 1);
handelNAND.data = in; mult = 1u << (mult + 2);
handelNAND.size = numsectors << 9; result = csd[8] & 3;
sdmmc_send_command(&handelNAND,0x52C19,sector_no); result = (result << 8) | csd[7];
inittarget(&handelSD); result = (result << 2) | (csd[6] >> 6);
return geterror(&handelNAND); result = (result + 1) * mult * block_len / 512;
}
break;
case 1:
result = csd[7] & 0x3f;
result = (result << 8) | csd[6];
result = (result << 8) | csd[5];
result = (result + 1) * 1024;
break;
default:
break; //Do nothing otherwise
}
return result;
} }
static uint32_t calcSDSize(uint8_t* csd, int type) static void InitSD()
{ {
uint32_t result=0; //NAND
if(type == -1) type = csd[14] >> 6; handleNAND.isSDHC = 0;
switch(type) handleNAND.SDOPT = 0;
{ handleNAND.res = 0;
case 0: handleNAND.initarg = 1;
{ handleNAND.clk = 0x80;
uint32_t block_len=csd[9]&0xf; handleNAND.devicenumber = 1;
block_len=1<<block_len;
uint32_t mult=(csd[4]>>7)|((csd[5]&3)<<1); //SD
mult=1<<(mult+2); handleSD.isSDHC = 0;
result=csd[8]&3; handleSD.SDOPT = 0;
result=(result<<8)|csd[7]; handleSD.res = 0;
result=(result<<2)|(csd[6]>>6); handleSD.initarg = 0;
result=(result+1)*mult*block_len/512; handleSD.clk = 0x80;
} handleSD.devicenumber = 0;
break;
case 1: *(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
result=csd[7]&0x3f; *(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
result=(result<<8)|csd[6]; *(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
result=(result<<8)|csd[5]; *(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
result=(result+1)*1024; *(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
break; *(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
} *(vu16*)0x10006104 = 0; //SDBLKLEN32
return result; *(vu16*)0x10006108 = 1; //SDBLKCOUNT32
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
*(vu16*)0x100060E0 |= 1u; //SDRESET
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
*(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
*(vu16*)0x10006026 = 512; //SDBLKLEN
*(vu16*)0x10006008 = 0; //SDSTOP
inittarget(&handleSD);
} }
void InitSD() static int Nand_Init()
{ {
//NAND inittarget(&handleNAND);
handelNAND.isSDHC = 0; ioDelay(0xF000);
handelNAND.SDOPT = 0;
handelNAND.res = 0; sdmmc_send_command(&handleNAND,0,0);
handelNAND.initarg = 1;
handelNAND.clk = 0x80; do {
handelNAND.devicenumber = 1; do {
sdmmc_send_command(&handleNAND,0x10701,0x100000);
//SD } while ( !(handleNAND.error & 1) );
handelSD.isSDHC = 0; } while((handleNAND.ret[0] & 0x80000000) == 0);
handelSD.SDOPT = 0;
handelSD.res = 0; sdmmc_send_command(&handleNAND,0x10602,0x0);
handelSD.initarg = 0; if (handleNAND.error & 0x4) return -1;
handelSD.clk = 0x80;
handelSD.devicenumber = 0; sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
if (handleNAND.error & 0x4) return -1;
//sdmmc_mask16(0x100,0x800,0);
//sdmmc_mask16(0x100,0x1000,0); sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
//sdmmc_mask16(0x100,0x0,0x402); if (handleNAND.error & 0x4) return -1;
//sdmmc_mask16(0xD8,0x22,0x2);
//sdmmc_mask16(0x100,0x2,0); handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
//sdmmc_mask16(0xD8,0x22,0); handleNAND.clk = 1;
//sdmmc_write16(0x104,0); setckl(1);
//sdmmc_write16(0x108,1);
//sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
//sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this if (handleNAND.error & 0x4) return -1;
//sdmmc_mask16(0x20,0,0x31D);
//sdmmc_mask16(0x22,0,0x837F); handleNAND.SDOPT = 1;
//sdmmc_mask16(0xFC,0,0xDB);
//sdmmc_mask16(0xFE,0,0xDB); sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
////sdmmc_write16(REG_SDCLKCTL,0x20); if (handleNAND.error & 0x4) return -1;
////sdmmc_write16(REG_SDOPT,0x40EE);
////sdmmc_mask16(0x02,0x3,0); sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
//sdmmc_write16(REG_SDCLKCTL,0x40); if (handleNAND.error & 0x4) return -1;
//sdmmc_write16(REG_SDOPT,0x40EB);
//sdmmc_mask16(0x02,0x3,0); sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
//sdmmc_write16(REG_SDBLKLEN,0x200); if (handleNAND.error & 0x4) return -1;
//sdmmc_write16(REG_SDSTOP,0);
sdmmc_send_command(&handleNAND,0x10410,0x200);
*(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32 if (handleNAND.error & 0x4) return -1;
*(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32
#ifdef DATA32_SUPPORT handleNAND.clk |= 0x200;
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
#else inittarget(&handleSD);
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
#endif return 0;
*(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2;
#ifdef DATA32_SUPPORT
*(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32
*(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL
*(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32
#else
*(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32
*(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL
*(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32
#endif
*(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32
*(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET
*(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET
*(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
*(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
*(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
*(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL
#ifdef DATA32_SUPPORT
*(volatile uint16_t*)0x10006024 = 0x20;
*(volatile uint16_t*)0x10006028 = 0x40EE;
#else
*(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20
*(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
#endif
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
*(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN
*(volatile uint16_t*)0x10006008 = 0; //SDSTOP
inittarget(&handelSD);
} }
int Nand_Init() static int SD_Init()
{ {
inittarget(&handelNAND); inittarget(&handleSD);
waitcycles(0xF000);
DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0,0);
DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
do
{
do
{
sdmmc_send_command(&handelNAND,0x10701,0x100000);
DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
} while ( !(handelNAND.error & 1) );
}
while((handelNAND.ret[0] & 0x80000000) == 0);
DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10602,0x0);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10403,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10609,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0],0);
handelNAND.clk = 1;
setckl(1);
sdmmc_send_command(&handelNAND,0x10407,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
handelNAND.SDOPT = 1;
sdmmc_send_command(&handelNAND,0x10506,0x3B70100);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10506,0x3B90100);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x1040D,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10410,0x200);
if((handelNAND.error & 0x4))return -1;
handelNAND.clk |= 0x200;
inittarget(&handelSD);
return 0;
}
int SD_Init() ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems
{
inittarget(&handelSD); //If not inserted
//waitcycles(0x3E8); if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1;
waitcycles(0xF000);
DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); sdmmc_send_command(&handleSD,0,0);
sdmmc_send_command(&handelSD,0,0); sdmmc_send_command(&handleSD,0x10408,0x1AA);
DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); //u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
sdmmc_send_command(&handelSD,0x10408,0x1AA); u32 temp = (handleSD.error & 0x1) << 0x1E;
//uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E;
uint32_t temp = (handelSD.error & 0x1) << 0x1E;
DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16*8, RGB(40, 40, 40), RGB(208, 208, 208));
//int count = 0;
uint32_t temp2 = 0;
do
{
do
{
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
temp2 = 1;
} while ( !(handelSD.error & 1) );
//DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
//DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
//DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
}
while((handelSD.ret[0] & 0x80000000) == 0);
//do
//{
// sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
// sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
//
// DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
// DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
// DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
//}
//while(!(handelSD.ret[0] & 0x80000000));
if(!((handelSD.ret[0] >> 30) & 1) || !temp) //int count = 0;
temp2 = 0; u32 temp2 = 0;
do {
handelSD.isSDHC = temp2; do {
//handelSD.isSDHC = (handelSD.ret[0] & 0x40000000); sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); temp2 = 1;
} while ( !(handleSD.error & 1) );
sdmmc_send_command(&handelSD,0x10602,0);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10403,0);
if((handelSD.error & 0x4)) return -1;
handelSD.initarg = handelSD.ret[0] >> 0x10;
DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10609,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0],-1);
handelSD.clk = 1;
setckl(1);
DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10507,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); } while((handleSD.ret[0] & 0x80000000) == 0);
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); if(!((handleSD.ret[0] >> 30) & 1) || !temp)
if((handelSD.error & 0x4)) return -1; temp2 = 0;
DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); handleSD.isSDHC = temp2;
handelSD.SDOPT = 1; sdmmc_send_command(&handleSD,0x10602,0);
sdmmc_send_command(&handelSD,0x10446,0x2); if (handleSD.error & 0x4) return -1;
if((handelSD.error & 0x4)) return -1;
sdmmc_send_command(&handleSD,0x10403,0);
DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); if (handleSD.error & 0x4) return -1;
handleSD.initarg = handleSD.ret[0] >> 0x10;
sdmmc_send_command(&handelSD,0x1040D,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1; sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
if (handleSD.error & 0x4) return -1;
DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
sdmmc_send_command(&handelSD,0x10410,0x200); handleSD.clk = 1;
if((handelSD.error & 0x4)) return -1; setckl(1);
handelSD.clk |= 0x200;
sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
return 0; if (handleSD.error & 0x4) return -1;
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
if (handleSD.error & 0x4) return -1;
handleSD.SDOPT = 1;
sdmmc_send_command(&handleSD,0x10446,0x2);
if (handleSD.error & 0x4) return -1;
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
if (handleSD.error & 0x4) return -1;
sdmmc_send_command(&handleSD,0x10410,0x200);
if (handleSD.error & 0x4) return -1;
handleSD.clk |= 0x200;
return 0;
} }
void sdmmc_sdcard_init() void sdmmc_sdcard_init()
{ {
DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2*8, RGB(40, 40, 40), RGB(208, 208, 208)); InitSD();
InitSD(); Nand_Init();
//SD_Init2(); SD_Init();
//Nand_Init();
Nand_Init();
DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3*8, RGB(40, 40, 40), RGB(208, 208, 208));
SD_Init();
DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4*8, RGB(40, 40, 40), RGB(208, 208, 208));
} }
int sdmmc_get_cid(int isNand, uint32_t *info)
{
struct mmcdevice *device;
if(isNand)
device = &handleNAND;
else
device = &handleSD;
inittarget(device);
// use cmd7 to put sd card in standby mode
// CMD7
{
sdmmc_send_command(device,0x10507,0);
//if((device->error & 0x4)) return -1;
}
// get sd card info
// use cmd10 to read CID
{
sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
//if((device->error & 0x4)) return -2;
for( int i = 0; i < 4; ++i ) {
info[i] = device->ret[i];
}
}
// put sd card back to transfer mode
// CMD7
{
sdmmc_send_command(device,0x10507,device->initarg << 0x10);
//if((device->error & 0x4)) return -3;
}
if(isNand)
{
inittarget(&handleSD);
}
return 0;
}

View File

@@ -1,52 +1,52 @@
#ifndef __SDMMC_H__ // Copyright 2014 Normmatt
#define __SDMMC_H__ // Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#define TRUE 1 #pragma once
#define FALSE 0
#include <stdint.h> #include "common.h"
#define SDMMC_BASE 0x10006000 #define SDMMC_BASE 0x10006000u
#define REG_SDCMD 0x00 #define REG_SDCMD 0x00
#define REG_SDPORTSEL 0x02 #define REG_SDPORTSEL 0x02
#define REG_SDCMDARG 0x04 #define REG_SDCMDARG 0x04
#define REG_SDCMDARG0 0x04 #define REG_SDCMDARG0 0x04
#define REG_SDCMDARG1 0x06 #define REG_SDCMDARG1 0x06
#define REG_SDSTOP 0x08 #define REG_SDSTOP 0x08
#define REG_SDBLKCOUNT 0x0a #define REG_SDBLKCOUNT 0x0a
#define REG_SDRESP0 0x0c #define REG_SDRESP0 0x0c
#define REG_SDRESP1 0x0e #define REG_SDRESP1 0x0e
#define REG_SDRESP2 0x10 #define REG_SDRESP2 0x10
#define REG_SDRESP3 0x12 #define REG_SDRESP3 0x12
#define REG_SDRESP4 0x14 #define REG_SDRESP4 0x14
#define REG_SDRESP5 0x16 #define REG_SDRESP5 0x16
#define REG_SDRESP6 0x18 #define REG_SDRESP6 0x18
#define REG_SDRESP7 0x1a #define REG_SDRESP7 0x1a
#define REG_SDSTATUS0 0x1c #define REG_SDSTATUS0 0x1c
#define REG_SDSTATUS1 0x1e #define REG_SDSTATUS1 0x1e
#define REG_SDIRMASK0 0x20 #define REG_SDIRMASK0 0x20
#define REG_SDIRMASK1 0x22 #define REG_SDIRMASK1 0x22
#define REG_SDCLKCTL 0x24 #define REG_SDCLKCTL 0x24
#define REG_SDBLKLEN 0x26
#define REG_SDOPT 0x28
#define REG_SDFIFO 0x30
#define REG_DATACTL 0xd8 #define REG_SDBLKLEN 0x26
#define REG_SDRESET 0xe0 #define REG_SDOPT 0x28
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? #define REG_SDFIFO 0x30
#define REG_DATACTL32 0x100 #define REG_SDDATACTL 0xd8
#define REG_SDBLKLEN32 0x104 #define REG_SDRESET 0xe0
#define REG_SDBLKCOUNT32 0x108 #define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
#define REG_SDFIFO32 0x10C
#define REG_CLK_AND_WAIT_CTL 0x138 #define REG_SDDATACTL32 0x100
#define REG_RESET_SDIO 0x1e0 #define REG_SDBLKLEN32 0x104
#define REG_SDBLKCOUNT32 0x108
#define REG_SDFIFO32 0x10C
#define REG_CLK_AND_WAIT_CTL 0x138
#define REG_RESET_SDIO 0x1e0
#define TMIO_STAT0_CMDRESPEND 0x0001 #define TMIO_STAT0_CMDRESPEND 0x0001
#define TMIO_STAT0_DATAEND 0x0004 #define TMIO_STAT0_DATAEND 0x0004
@@ -97,88 +97,33 @@
#define TMIO_MASK_ALL 0x837f031d #define TMIO_MASK_ALL 0x837f031d
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ #define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) #define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
#ifdef __cplusplus typedef struct mmcdevice {
extern "C" { vu8* data;
#endif u32 size;
u32 error;
u16 stat0;
u16 stat1;
u32 ret[4];
u32 initarg;
u32 isSDHC;
u32 clk;
u32 SDOPT;
u32 devicenumber;
u32 total_size; //size in sectors of the device
u32 res;
} mmcdevice;
typedef struct mmcdevice { mmcdevice *getMMCDevice(int drive);
uint8_t* data;
uint32_t size;
uint32_t error;
uint16_t stat0;
uint16_t stat1;
uint32_t ret[4];
uint32_t initarg;
uint32_t isSDHC;
uint32_t clk;
uint32_t SDOPT;
uint32_t devicenumber;
uint32_t total_size; //size in sectors of the device
uint32_t res;
} mmcdevice;
void sdmmc_sdcard_init();
int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
mmcdevice *getMMCDevice(int drive);
void InitSD();
int Nand_Init();
int SD_Init();
#ifdef __cplusplus void sdmmc_sdcard_init();
}; u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
#endif u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
//--------------------------------------------------------------------------------- u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
static inline uint16_t sdmmc_read16(uint16_t reg) {
//---------------------------------------------------------------------------------
return *(volatile uint16_t*)(SDMMC_BASE + reg);
}
//--------------------------------------------------------------------------------- int sdmmc_get_cid( int isNand, uint32_t *info);
static inline void sdmmc_write16(uint16_t reg, uint16_t val) {
//---------------------------------------------------------------------------------
*(volatile uint16_t*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline uint32_t sdmmc_read32(uint16_t reg) {
//---------------------------------------------------------------------------------
return *(volatile uint32_t*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write32(uint16_t reg, uint32_t val) {
//---------------------------------------------------------------------------------
*(volatile uint32_t*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) {
//---------------------------------------------------------------------------------
uint16_t val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
sdmmc_write16(reg, val);
}
static inline void setckl(uint32_t data)
{
sdmmc_mask16(REG_SDCLKCTL,0x100,0);
sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF);
sdmmc_mask16(REG_SDCLKCTL,0x0,0x100);
}
#endif

View File

@@ -1,200 +1,416 @@
/* /*
* firm.c * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
#include "firm.h" #include "firm.h"
#include "config.h"
#include "utils.h"
#include "fs.h"
#include "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "fs.h" #include "cache.h"
#include "emunand.h" #include "emunand.h"
#include "crypto.h" #include "crypto.h"
#include "draw.h"
#include "screen.h"
#include "buttons.h"
#include "pin.h"
#include "../build/injector.h"
firmHeader *firmLocation = (firmHeader *)0x24000000; extern u16 launchedFirmTIDLow[8]; //defined in start.s
firmSectionHeader *section;
vu32 *arm11Entry = (vu32*)0x1FFFFFF8;
u32 firmSize = 0;
u8 mode = 1,
console = 1,
a9lhSetup = 0,
updatedSys = 0;
u16 pressed;
void setupCFW(void){ static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section;
u32 config,
emuOffset;
bool isN3DS,
isDevUnit,
isFirmlaunch;
FirmwareSource firmSource;
void main(void)
{
bool isA9lh;
u32 configTemp,
emuHeader;
FirmwareType firmType;
FirmwareSource nandType;
ConfigurationStatus needConfig;
//Detect the console being used //Detect the console being used
if(PDN_MPCORE_CFG == 1) console = 0; isN3DS = PDN_MPCORE_CFG == 7;
//Get pressed buttons //Detect dev units
pressed = HID_PAD; isDevUnit = CFG_UNITINFO != 0;
//Determine if A9LH is installed via PDN_SPI_CNT and an user flag //Mount filesystems. CTRNAND will be mounted only if/when needed
if((*((u8*)0x101401C0) == 0x0) || fileExists("/rei/installeda9lh")){ mountFs();
a9lhSetup = 1;
//Check flag for > 9.2 SysNAND const char configPath[] = "/luma/config.bin";
if(fileExists("/rei/updatedsysnand")) updatedSys = 1;
//Attempt to read the configuration file
needConfig = fileRead(&config, configPath) ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
//Determine if this is a firmlaunch boot
if(launchedFirmTIDLow[5] != 0)
{
if(needConfig == CREATE_CONFIGURATION) mcuReboot();
isFirmlaunch = true;
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = launchedFirmTIDLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTIDLow[5] - u'0');
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
isA9lh = BOOTCONFIG(3, 1) != 0;
}
else
{
//Get pressed buttons
u32 pressed = HID_PAD;
isFirmlaunch = false;
firmType = NATIVE_FIRM;
//Determine if booting with A9LH
isA9lh = !PDN_SPI_CNT;
//Determine if the user chose to use the SysNAND FIRM as default for a R boot
bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
//Save old options and begin saving the new boot configuration
configTemp = (config & 0xFFFFFFC0) | ((u32)isA9lh << 3);
//If it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7)
{
nandType = FIRMWARE_SYSNAND;
firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing
configTemp |= 1 << 4;
}
/* Else, force the last used boot options unless a button is pressed
or the no-forcing flag is set */
else if(!pressed && !BOOTCONFIG(4, 1))
{
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
}
}
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
PINData pin;
bool pinExists = CONFIG(7) && readPin(&pin);
//If we get here we should check the PIN (if it exists) in all cases
if(pinExists) verifyPin(&pin);
//If no configuration file exists or SELECT is held, load configuration menu
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
if(shouldLoadConfigurationMenu)
{
configureCFW();
if(!pinExists && CONFIG(7)) newPin();
chrono(2);
//Update pressed buttons
pressed = HID_PAD;
}
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
{
nandType = FIRMWARE_SYSNAND;
firmSource = FIRMWARE_SYSNAND;
//Flag to tell loader to init SD
configTemp |= 1 << 5;
}
else
{
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
/* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload (the PIN, if any, has been verified)*/
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
if(shouldLoadPayload) loadPayload(pressed);
if(!CONFIG(6)) loadSplash();
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
if(pressed & BUTTON_R1)
{
nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
}
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */
else
{
nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
firmSource = nandType;
}
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */
if(nandType != FIRMWARE_SYSNAND && (CONFIG(2) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
}
}
} }
/* If L is pressed, and on an updated SysNAND setup the SAFE MODE combo //If we need to boot emuNAND, make sure it exists
is not pressed, boot 9.0 FIRM */ if(nandType != FIRMWARE_SYSNAND)
if((pressed & BUTTON_L1) && !(updatedSys && pressed == SAFEMODE)) mode = 0; {
locateEmuNAND(&emuOffset, &emuHeader, &nandType);
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
}
//Same if we're using emuNAND as the FIRM source
else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNAND(&emuOffset, &emuHeader, &firmSource);
if(!isFirmlaunch)
{
configTemp |= (u32)nandType | ((u32)firmSource << 2);
/* If the configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */
if((configTemp & 0xFFFFFFEF) != config)
{
//Merge the new options and new boot configuration
config = (config & 0xFFFFFFC0) | (configTemp & 0x3F);
if(!fileWrite(&config, configPath, 4))
{
createDirectory("luma");
if(!fileWrite(&config, configPath, 4))
error("Error writing the configuration file");
}
}
}
u32 firmVersion = loadFirm(firmType);
switch(firmType)
{
case NATIVE_FIRM:
patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break;
case SAFE_FIRM:
patchSafeFirm();
break;
default:
//Skip patching on unsupported O3DS AGB/TWL FIRMs
if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
break;
}
launchFirm(firmType);
} }
//Load firm into FCRAM static inline u32 loadFirm(FirmwareType firmType)
u8 loadFirm(void){
//If not using an A9LH setup, load 9.0 FIRM from NAND
if(!a9lhSetup && !mode){
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8*)firmLocation, firmSize, console);
//Check for correct decryption
if(memcmp((u8*)firmLocation, "FIRM", 4) != 0) return 1;
}
//Load FIRM from SD
else{
char firmPath[] = "/rei/firmware.bin";
char firmPath2[] = "/rei/firmware90.bin";
char *pathPtr = mode ? firmPath : firmPath2;
firmSize = fileSize(pathPtr);
if (!firmSize) return 1;
fileRead((u8*)firmLocation, pathPtr, firmSize);
}
section = firmLocation->section;
//Check that the loaded FIRM matches the console
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) return 1;
if(console) arm9loader((u8*)firmLocation + section[2].offset, mode);
return 0;
}
//Nand redirection
u8 loadEmu(void){
u32 emuOffset = 0,
emuHeader = 0,
emuRead = 0,
emuWrite = 0,
sdmmcOffset = 0,
mpuOffset = 0,
emuCodeOffset = 0;
//Read emunand code from SD
char path[] = "/rei/emunand/emunand.bin";
u32 size = fileSize(path);
if (!size) return 1;
if(!console || !mode) nandRedir[5] = 0xA4;
//Find offset for emuNAND code from the offset in nandRedir
u8 *emuCodeTmp = &nandRedir[4];
emuCodeOffset = *(u32*)emuCodeTmp - (u32)section[2].address +
section[2].offset + (u32)firmLocation;
fileRead((u8*)emuCodeOffset, path, size);
//Find and patch emunand related offsets
u32 *pos_sdmmc = memsearch((u32*)emuCodeOffset, "SDMC", size, 4);
u32 *pos_offset = memsearch((u32*)emuCodeOffset, "NAND", size, 4);
u32 *pos_header = memsearch((u32*)emuCodeOffset, "NCSD", size, 4);
getSDMMC(firmLocation, &sdmmcOffset, firmSize);
getEmunandSect(&emuOffset, &emuHeader);
getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite);
getMPU(firmLocation, &mpuOffset, firmSize);
*pos_sdmmc = sdmmcOffset;
*pos_offset = emuOffset;
*pos_header = emuHeader;
//Patch emuNAND code in memory for O3DS and 9.0 N3DS
if(!console || !mode){
u32 *pos_instr = memsearch((u32*)emuCodeOffset, "\xA6\x01\x08\x30", size, 4);
memcpy((u8*)pos_instr, emuInstr, sizeof(emuInstr));
}
//Add emunand hooks
memcpy((u8*)emuRead, nandRedir, sizeof(nandRedir));
memcpy((u8*)emuWrite, nandRedir, sizeof(nandRedir));
//Set MPU for emu code region
memcpy((u8*)mpuOffset, mpu, sizeof(mpu));
return 0;
}
//Patches
u8 patchFirm(void){
/* If L or R aren't pressed on a 9.0/9.2 SysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 SysNAND, boot emuNAND */
if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) ||
(!updatedSys && mode && !(pressed & (BUTTON_L1 | BUTTON_R1)))){
if (loadEmu()) return 1;
}
else if (a9lhSetup){
//Patch FIRM partitions writes on SysNAND to protect A9LH
u32 writeOffset = 0;
getFIRMWrite(firmLocation, firmSize, &writeOffset);
memcpy((u8*)writeOffset, FIRMblock, sizeof(FIRMblock));
}
//Disable signature checks
u32 sigOffset = 0,
sigOffset2 = 0;
getSignatures(firmLocation, firmSize, &sigOffset, &sigOffset2);
memcpy((u8*)sigOffset, sigPat1, sizeof(sigPat1));
memcpy((u8*)sigOffset2, sigPat2, sizeof(sigPat2));
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){
u32 rebootOffset = 0,
fOpenOffset = 0;
//Read reboot code from SD
char path[] = "/rei/reboot/reboot.bin";
u32 size = fileSize(path);
if (!size) return 1;
getReboot(firmLocation, firmSize, &rebootOffset);
fileRead((u8*)rebootOffset, path, size);
//Calculate the fOpen offset and put it in the right location
u32 *pos_fopen = memsearch((u32*)rebootOffset, "OPEN", size, 4);
getfOpen(firmLocation, firmSize, &fOpenOffset);
*pos_fopen = fOpenOffset;
//Write patched FIRM to SD
if(fileWrite((u8*)firmLocation, "/rei/patched_firmware.bin", firmSize) != 0) return 1;
}
return 0;
}
//De-initialize the screens, fixes N3DS 3D
void __attribute__((naked)) deinitScreen(void)
{ {
*arm11Entry = 0; section = firm->section;
*(vu32*)0x10202A44 = 0; //Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
*(vu32*)0x10202244 = 0; u32 firmVersion = firmRead(firm, (u32)firmType);
*(vu32*)0x1020200C = 0;
*(vu32*)0x10202014 = 0;
while (!*arm11Entry); if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
((void (*)())*arm11Entry)(); {
//We can't boot < 3.x NANDs
if(firmVersion < 0x18)
error("An old unsupported NAND has been detected.\nLuma3DS is unable to boot it.");
//We can't boot a 4.x NATIVE_FIRM, load one from SD
if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
//No assumption regarding FIRM version
firmVersion = 0xffffffff;
}
else decryptExeFs((u8 *)firm);
return firmVersion;
} }
//Firmlaunchhax static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
void launchFirm(void){ {
u8 *arm9Section = (u8 *)firm + section[2].offset;
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
//Copy firm partitions to respective memory locations if(isN3DS)
memcpy(section[0].address, (u8*)firmLocation + section[0].offset, section[0].size); {
memcpy(section[1].address, (u8*)firmLocation + section[1].offset, section[1].size); //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size); arm9Loader(arm9Section);
*arm11Entry = (u32)deinitScreen; firm->arm9Entry = (u8 *)0x801B01C;
while (*arm11Entry); }
*arm11Entry = (u32)firmLocation->arm11Entry;
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
//Final jump to arm9 binary else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
console ? ((void (*)())0x801B01C)() : ((void (*)())firmLocation->arm9Entry)();
//Find the Process9 .code location, size and memory address
u32 process9Size,
process9MemAddr;
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
//Apply signature patches
patchSignatureChecks(process9Offset, process9Size);
//Apply emuNAND patches
if(nandType != FIRMWARE_SYSNAND)
{
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
//Apply firmlaunch patches
patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
//11.0 FIRM patches
if(firmVersion >= (isN3DS ? 0x21 : 0x52))
{
//Apply anti-anti-DG patches
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
//Restore svcBackdoor
reimplementSvcBackdoor(arm11Section1, section[1].size);
}
implementSvcGetCFWInfo(arm11Section1, section[1].size);
}
static inline void patchLegacyFirm(FirmwareType firmType)
{
if(isN3DS)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader((u8 *)firm + section[3].offset);
firm->arm9Entry = (u8 *)0x801301C;
}
applyLegacyFirmPatches((u8 *)firm, firmType);
if(firmType == TWL_FIRM && CONFIG(8))
patchTwlBg((u8 *)firm + section[1].offset);
}
static inline void patchSafeFirm(void)
{
u8 *arm9Section = (u8 *)firm + section[2].offset;
if(isN3DS)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size);
}
else patchFirmWriteSafe(arm9Section, section[2].size);
}
static inline void copySection0AndInjectSystemModules(void)
{
u8 *arm11Section0 = (u8 *)firm + section[0].offset;
struct
{
u32 size;
const u8 *addr;
} modules[5];
u32 n = 0,
loaderIndex;
u8 *pos = arm11Section0;
for(u8 *end = pos + section[0].size; pos < end; pos += modules[n++].size)
{
modules[n].addr = pos;
modules[n].size = *(u32 *)(pos + 0x104) * 0x200;
if(memcmp(modules[n].addr + 0x200, "loader", 7) == 0) loaderIndex = n;
}
modules[loaderIndex].addr = injector;
modules[loaderIndex].size = injector_size;
pos = section[0].address;
for(u32 i = 0; i < n; pos += modules[i++].size)
memcpy(pos, modules[i].addr, modules[i].size);
}
static inline void launchFirm(FirmwareType firmType)
{
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
u32 sectionNum;
if(firmType == NATIVE_FIRM)
{
copySection0AndInjectSystemModules();
sectionNum = 1;
}
else sectionNum = 0;
//Copy FIRM sections to respective memory locations
for(; sectionNum < 4 && section[sectionNum].size; sectionNum++)
memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size);
//Determine the ARM11 entry to use
vu32 *arm11;
if(isFirmlaunch) arm11 = (u32 *)0x1FFFFFFC;
else
{
deinitScreens();
arm11 = (u32 *)0x1FFFFFF8;
}
//Set ARM11 kernel entrypoint
*arm11 = (u32)firm->arm11Entry;
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireICache();
//Final jump to ARM9 kernel
((void (*)())firm->arm9Entry)();
} }

View File

@@ -1,22 +1,57 @@
/* /*
* firm.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
#ifndef FIRM_INC
#define FIRM_INC #pragma once
#include "types.h" #include "types.h"
#define PDN_MPCORE_CFG (*(u8*)0x10140FFC) //FIRM Header layout
#define HID_PAD ((~*(u16*)0x10146000) & 0xFFF) typedef struct firmSectionHeader {
#define BUTTON_R1 (1 << 8) u32 offset;
#define BUTTON_L1 (1 << 9) u8 *address;
#define SAFEMODE (BUTTON_L1 | BUTTON_R1 | 1 | (1 << 6)) u32 size;
u32 procType;
u8 hash[0x20];
} firmSectionHeader;
void setupCFW(void); typedef struct firmHeader {
u8 loadFirm(void); u32 magic;
u8 patchFirm(void); u32 reserved1;
void launchFirm(void); u8 *arm11Entry;
u8 *arm9Entry;
u8 reserved2[0x30];
firmSectionHeader section[4];
} firmHeader;
#endif typedef enum ConfigurationStatus
{
DONT_CONFIGURE = 0,
MODIFY_CONFIGURATION = 1,
CREATE_CONFIGURATION = 2
} ConfigurationStatus;
static inline u32 loadFirm(FirmwareType firmType);
static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void);
static inline void copySection0AndInjectSystemModules(void);
static inline void launchFirm(FirmwareType firmType);

144
source/font.h Normal file
View File

@@ -0,0 +1,144 @@
/*
This file was autogenerated by raw2c.
Visit http://www.devkitpro.org
*/
//---------------------------------------------------------------------------------
#ifndef _font_h_
#define _font_h_
//---------------------------------------------------------------------------------
static const unsigned char font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00,
0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00,
0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00,
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e,
0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00,
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00,
0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00,
0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00,
0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00,
0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00,
0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00,
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00,
0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00,
0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00,
0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06,
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00,
0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00,
0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00,
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00,
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78,
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00,
0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00,
0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00,
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00,
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00,
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70,
0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00,
0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00,
0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00,
0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00,
0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00,
0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00,
0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00,
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40,
0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00,
0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00,
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00,
0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00,
0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00,
0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00,
0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00,
0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00,
0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const int font_size = sizeof(font);
//---------------------------------------------------------------------------------
#endif //_font_h_
//---------------------------------------------------------------------------------

View File

@@ -1,97 +1,182 @@
/* /*
* fs.c * This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
#include <stddef.h>
#include "fs.h" #include "fs.h"
#include "memory.h"
#include "cache.h"
#include "screen.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
#include "buttons.h"
#include "../build/loader.h"
static FATFS fs; static FATFS sdFs,
nandFs;
int mountSD() void mountFs(void)
{ {
if (f_mount(&fs, "0:", 1) != FR_OK) { f_mount(&sdFs, "0:", 1);
//printF("Failed to mount SD card!"); f_mount(&nandFs, "1:", 0);
return 1;
}
//printF("Mounted SD card");
return 0;
} }
int unmountSD() u32 fileRead(void *dest, const char *path)
{ {
if (f_mount(NULL, "0:", 1) != FR_OK) { FIL file;
//printF("Failed to mount SD card!"); u32 size;
return 1;
if(f_open(&file, path, FA_READ) == FR_OK)
{
unsigned int read;
size = f_size(&file);
if(dest != NULL)
f_read(&file, dest, size, &read);
f_close(&file);
} }
//printF("Unmounted SD card"); else size = 0;
return 0;
return size;
} }
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset){ u32 getFileSize(const char *path)
FRESULT fr; {
FIL fp; return fileRead(NULL, path);
unsigned int br = 0; }
fr = f_open(&fp, path, FA_READ); bool fileWrite(const void *buffer, const char *path, u32 size)
if (fr != FR_OK)goto error; {
FIL file;
if (!size) size = f_size(&fp);
if (offset) { if(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK)
fr = f_lseek(&fp, offset); {
if (fr != FR_OK) goto error; unsigned int written;
f_write(&file, buffer, size, &written);
f_close(&file);
return true;
} }
fr = f_read(&fp, dest, size, &br); return false;
if (fr != FR_OK) goto error;
fr = f_close(&fp);
if (fr != FR_OK) goto error;
return 0;
error:
f_close(&fp);
return fr;
} }
int fileRead(u8 *dest, const char *path, u32 size){ void createDirectory(const char *path)
return fileReadOffset(dest, path, size, 0); {
f_mkdir(path);
} }
int fileWrite(const u8 *buffer, const char *path, u32 size){ void loadPayload(u32 pressed)
FRESULT fr = 1; {
FIL fp; const char *pattern;
unsigned int br = 0;
f_unlink(path); if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
if(f_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK){ else if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
fr = f_write(&fp, buffer, size, &br); else if(pressed & BUTTON_UP) pattern = PATTERN("up");
f_close(&fp); else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
if (fr == FR_OK && br == size) return 0; else if(pressed & BUTTON_X) pattern = PATTERN("x");
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
else if(pressed & BUTTON_A) pattern = PATTERN("a");
else if(pressed & BUTTON_START) pattern = PATTERN("start");
else pattern = PATTERN("select");
DIR dir;
FILINFO info;
char path[28] = "/luma/payloads";
FRESULT result = f_findfirst(&dir, &info, path, pattern);
f_closedir(&dir);
if(result == FR_OK && info.fname[0])
{
initScreens();
u32 *const loaderAddress = (u32 *)0x24FFFF00;
memcpy(loaderAddress, loader, loader_size);
path[14] = '/';
memcpy(&path[15], info.altname, 13);
loaderAddress[1] = fileRead((void *)0x24F00000, path);
flushDCacheRange(loaderAddress, loader_size);
flushICacheRange(loaderAddress, loader_size);
((void (*)())loaderAddress)();
} }
return fr;
} }
int fileSize(const char* path){ u32 firmRead(void *dest, u32 firmType)
FRESULT fr; {
FIL fp; const char *firmFolders[4][2] = {{ "00000002", "20000002" },
int size = 0; { "00000102", "20000102" },
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
fr = f_open(&fp, path, FA_READ); char path[48] = "1:/title/00040138/00000000/content";
if (fr != FR_OK)goto error; memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
size = f_size(&fp);
error:
f_close(&fp);
return size;
}
int fileExists(const char* path){ DIR dir;
FRESULT fr; FILINFO info;
FIL fp;
int exists = 1; f_opendir(&dir, path);
fr = f_open(&fp, path, FA_READ);
if (fr != FR_OK)exists = 0; u32 firmVersion = 0xFFFFFFFF;
f_close(&fp);
return exists; //Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
{
//Not a cxi
if(info.altname[9] != 'A') continue;
//Convert the .app name to an integer
u32 tempVersion = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++)
{
tempVersion <<= 4;
tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
}
//Found an older cxi
if(tempVersion < firmVersion) firmVersion = tempVersion;
}
f_closedir(&dir);
//Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14);
//Last digit of the .app
u32 i = 42;
//Convert back the .app name from integer to array
u32 tempVersion = firmVersion;
while(tempVersion)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[tempVersion & 0xF];
tempVersion >>= 4;
}
fileRead(dest, path);
return firmVersion;
} }

View File

@@ -1,18 +1,37 @@
/* /*
* fs.h * This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
#ifndef __fs_h__ #pragma once
#define __fs_h__
#include "types.h" #include "types.h"
int mountSD(); #define PATTERN(a) a "_*.bin"
int unmountSD();
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset);
int fileRead(u8 *dest, const char *path, u32 size);
int fileWrite(const u8 *buffer, const char *path, u32 size);
int fileSize(const char* path);
int fileExists(const char* path);
#endif extern bool isN3DS;
void mountFs(void);
u32 fileRead(void *dest, const char *path);
u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size);
void createDirectory(const char *path);
void loadPayload(u32 pressed);
u32 firmRead(void *dest, u32 firmType);

136
source/i2c.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "i2c.h"
//-----------------------------------------------------------------------------
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
{1, 0x2E}, {1, 0x40}, {1, 0x44},
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
};
static inline u8 i2cGetDeviceBusId(u8 device_id)
{
return dev_data[device_id].bus_id;
}
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
{
return dev_data[device_id].reg_addr;
}
//-----------------------------------------------------------------------------
static vu8 *reg_data_addrs[] = {
(vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
(vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
(vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
};
static inline vu8 *i2cGetDataReg(u8 bus_id)
{
return reg_data_addrs[bus_id];
}
//-----------------------------------------------------------------------------
static vu8 *reg_cnt_addrs[] = {
(vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
(vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
(vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
};
static inline vu8 *i2cGetCntReg(u8 bus_id)
{
return reg_cnt_addrs[bus_id];
}
//-----------------------------------------------------------------------------
static inline void i2cWaitBusy(u8 bus_id)
{
while (*i2cGetCntReg(bus_id) & 0x80);
}
static inline u32 i2cGetResult(u8 bus_id)
{
i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1;
}
static void i2cStop(u8 bus_id, u8 arg0)
{
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
}
//-----------------------------------------------------------------------------
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
{
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id);
}
static u32 i2cSelectRegister(u8 bus_id, u8 reg)
{
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id);
}
//-----------------------------------------------------------------------------
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
{
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for(u32 i = 0; i < 8; i++)
{
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
{
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0);
if(i2cGetResult(bus_id))
return 1;
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
return 0;
}

44
source/i2c.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* Thanks to the everyone who contributed in the development of this file
*/
#pragma once
#include "types.h"
#define I2C1_REG_OFF 0x10161000
#define I2C2_REG_OFF 0x10144000
#define I2C3_REG_OFF 0x10148000
#define I2C_REG_DATA 0
#define I2C_REG_CNT 1
#define I2C_REG_CNTEX 2
#define I2C_REG_SCL 4
#define I2C_DEV_MCU 3
#define I2C_DEV_GYRO 10
#define I2C_DEV_IR 13
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data);

View File

@@ -1,21 +0,0 @@
/*
* main.c
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*
* Minimalist CFW for N3DS
*/
#include "fs.h"
#include "firm.h"
#include "draw.h"
u8 main(){
mountSD();
loadSplash();
setupCFW();
if (loadFirm()) return 1;
if (patchFirm()) return 1;
launchFirm();
return 0;
}

View File

@@ -1,42 +1,85 @@
/* /*
* memory.c * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
/*
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#include "memory.h" #include "memory.h"
void memcpy32(u32 *dest, u32 *src, u32 size){ void memcpy(void *dest, const void *src, u32 size)
for (u32 i = 0; i < size; i++) dest[i] = src[i]; {
} u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
void memcpy(void *dest, const void *src, u32 size){ for(u32 i = 0; i < size; i++)
char *destc = (char *)dest;
const char *srcc = (const char *)src;
u32 i; for (i = 0; i < size; i++) {
destc[i] = srcc[i]; destc[i] = srcc[i];
}
} }
void memset(void *dest, int filler, u32 size){ void memset32(void *dest, u32 filler, u32 size)
char *destc = (char *)dest; {
u32 i; for (i = 0; i < size; i++) { u32 *dest32 = (u32 *)dest;
destc[i] = filler;
} for (u32 i = 0; i < size / 4; i++)
dest32[i] = filler;
} }
int memcmp(const void *buf1, const void *buf2, u32 size){ int memcmp(const void *buf1, const void *buf2, u32 size)
const char *buf1c = (const char *)buf1; {
const char *buf2c = (const char *)buf2; const u8 *buf1c = (const u8 *)buf1;
u32 i; for (i = 0; i < size; i++) { const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i]; int cmp = buf1c[i] - buf2c[i];
if (cmp) return cmp; if(cmp) return cmp;
} }
return 0; return 0;
} }
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search){ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
for (void *pos = start_pos + size - size_search; pos >= start_pos; pos--) { {
if (memcmp(pos, search, size_search) == 0) return pos; const u8 *patternc = (const u8 *)pattern;
//Preprocessing
u32 table[256];
for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1;
for(u32 i = 0; i < patternSize; ++i)
table[patternc[i]] = patternSize - i;
//Searching
u32 j = 0;
while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j;
j += table[startPos[j + patternSize]];
} }
return NULL; return NULL;
} }

View File

@@ -1,17 +1,36 @@
/* /*
* memory.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
#ifndef MEM_INC
#define MEM_INC
/*
* Quick Search algorithm adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#pragma once
#include "types.h" #include "types.h"
void memcpy(void *dest, const void *src, u32 size); void memcpy(void *dest, const void *src, u32 size);
void memcpy32(u32 *dest, u32 *src, u32 size); void memset32(void *dest, u32 filler, u32 size);
void memset(void *dest, int filler, u32 size);
int memcmp(const void *buf1, const void *buf2, u32 size); int memcmp(const void *buf1, const void *buf2, u32 size);
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search); u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
#endif

View File

@@ -1,69 +1,266 @@
/* /*
* patches.c * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/ */
#include "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "config.h"
#include "../build/rebootpatch.h"
#include "../build/svcGetCFWInfopatch.h"
#include "../build/twl_k11modulespatch.h"
/************************************************** static u32 *arm11ExceptionsPage = NULL;
* Patches static u32 *arm11SvcTable = NULL;
**************************************************/ static u32 *arm11SvcHandler = NULL;
/* static u8 *freeK11Space = NULL; //other than the one used for svcBackdoor
* MPU
*/ static void findArm11ExceptionsPageAndSvcHandlerAndTable(u8 *pos, u32 size)
u8 mpu[0x2C] = { //MPU shit {
0x03, 0x00, 0x36, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x36, 0x00, const u8 arm11ExceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5};
0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08,
0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x08 if(arm11ExceptionsPage == NULL) arm11ExceptionsPage = (u32 *)memsearch(pos, arm11ExceptionsPagePattern, size, 4) - 0xB;
if((arm11SvcTable == NULL || arm11SvcHandler == NULL) && arm11ExceptionsPage != NULL)
{
u32 svcOffset = (-((arm11ExceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
arm11SvcHandler = arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
}
}
static void findFreeK11Space(u8 *pos, u32 size)
{
if(freeK11Space == NULL)
{
const u8 bogus_pattern[] = { 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF,
0x2F, 0xE1, 0x00, 0x10, 0xA0, 0xE3, 0x00, 0x10, 0xC0, 0xE5,
0x1E, 0xFF, 0x2F, 0xE1 };
u32 *someSpace = (u32 *)memsearch(pos, bogus_pattern, size, 24);
// We couldn't find the place where to begin our search of an empty block
if (someSpace == NULL)
return;
// Advance until we reach the padding area (filled with 0xFF)
u32 *freeSpace;
for(freeSpace = someSpace; *freeSpace != 0xFFFFFFFF; freeSpace++);
freeK11Space = (u8 *)freeSpace;
}
}
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{
u8 *off = memsearch(pos, "ess9", size, 4);
*process9Size = *(u32 *)(off - 0x60) * 0x200;
*process9MemAddr = *(u32 *)(off + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
}
void patchSignatureChecks(u8 *pos, u32 size)
{
const u16 sigPatch[2] = {0x2000, 0x4770};
//Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4),
*off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1);
*off = sigPatch[0];
off2[0] = sigPatch[0];
off2[1] = sigPatch[1];
}
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
{
//Look for firmlaunch code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
u8 *off = memsearch(pos, pattern, size, 4) - 0x10;
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
//Copy firmlaunch code
memcpy(off, reboot, reboot_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
}
void patchFirmWrites(u8 *pos, u32 size)
{
const u16 writeBlock[2] = {0x2000, 0x46C0};
//Look for FIRM writing code
u8 *const off1 = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, 4);
off2[0] = writeBlock[0];
off2[1] = writeBlock[1];
}
void patchFirmWriteSafe(u8 *pos, u32 size)
{
const u16 writeBlockSafe[2] = {0x2400, 0xE01D};
//Look for FIRM writing code
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4);
off[0] = writeBlockSafe[0];
off[1] = writeBlockSafe[1];
}
void reimplementSvcBackdoor(u8 *pos, u32 size)
{
//Official implementation of svcBackdoor
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
0x30, 0xFF, 0x2F, 0xE1, //blx r0
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
if(!arm11SvcTable[0x7B])
{
u32 *freeSpace;
for(freeSpace = arm11ExceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
memcpy(freeSpace, svcBackdoor, 40);
arm11SvcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)arm11ExceptionsPage);
}
}
void implementSvcGetCFWInfo(u8 *pos, u32 size)
{
const char *rev = REVISION;
bool isRelease;
findArm11ExceptionsPageAndSvcHandlerAndTable(pos, size);
findFreeK11Space(pos, size);
memcpy(freeK11Space, svcGetCFWInfo, svcGetCFWInfo_size);
CFWInfo *info = (CFWInfo *)memsearch(freeK11Space, "LUMA", svcGetCFWInfo_size, 4);
info->commitHash = COMMIT_HASH;
info->config = config;
info->versionMajor = (u8)(rev[1] - '0');
info->versionMinor = (u8)(rev[3] - '0');
if(rev[4] == '.')
{
info->versionBuild = (u8)(rev[5] - '0');
isRelease = rev[6] == 0;
}
else
isRelease = rev[4] == 0;
info->flags = 0 /* master branch */ | (((isRelease) ? 1 : 0) << 1) /* is release */;
arm11SvcTable[0x2E] = 0xFFF00000 + freeK11Space - pos; //stubbed svc
freeK11Space += svcGetCFWInfo_size;
}
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
{
const u8 pattern[] = {0x0A, 0x81, 0x42, 0x02};
u8 *off = memsearch(pos, pattern, size, 4);
if(off != NULL) off[4] = 0xE0;
}
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
{
const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
},
agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
}; };
u8 nandRedir[0x08] = {0x00, 0x4C, 0xA0, 0x47, 0xC0, 0xA5, 0x01, 0x08}; //Branch to emunand function /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
/* //Patch
* Sig checks for(u32 i = 0; i < numPatches; i++)
*/ {
u8 sigPat1[2] = {0x00, 0x20}; switch(patches[i].type)
u8 sigPat2[4] = {0x00, 0x20, 0x70, 0x47}; {
u8 FIRMblock[4] = {0x00, 0x20, 0xC0, 0x46}; case 0:
u8 emuInstr[5] = {0xA5, 0x01, 0x08, 0x30, 0xA5}; memcpy(pos + patches[i].offset[isN3DS ? 1 : 0], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break;
/************************************************** case 2:
* Functions *(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0] + 2) = 0;
**************************************************/ case 1:
*(u16 *)(pos + patches[i].offset[isN3DS ? 1 : 0]) = patches[i].patch.type1;
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2){ break;
//Look for signature checks }
unsigned char pattern[] = {0xC0, 0x1C, 0x76, 0xE7}; }
unsigned char pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
*off = (u32)memsearch(pos, pattern, size, 4);
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
} }
void getReboot(void *pos, u32 size, u32 *off){ void patchTwlBg(u8 *pos)
//Look for FIRM reboot code {
unsigned char pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; u8 *dst = pos + ((isN3DS) ? 0xFEA4 : 0xFCA0);
u16 *src1 = (u16 *)(pos + ((isN3DS) ? 0xE38 : 0xE3C)), *src2 = (u16 *)(pos + ((isN3DS) ? 0xE54 : 0xE58));
memcpy(dst, twl_k11modules, twl_k11modules_size); //install k11 hook
u32 *off;
for(off = (u32 *)dst; *off != 0xABCDABCD; off++);
*off = (isN3DS) ? 0xCDE88 : 0xCD5F8; //dev SRL launcher offset
//Construct BLX instructions:
src1[0] = 0xF000 | ((((u32)dst - (u32)src1 - 4) & (0xFFF << 11)) >> 12);
src1[1] = 0xE800 | ((((u32)dst - (u32)src1 - 4) & 0xFFF) >> 1);
*off = (u32)memsearch(pos, pattern, size, 4) - 0x10; src2[0] = 0xF000 | ((((u32)dst - (u32)src2 - 4) & (0xFFF << 11)) >> 12);
} src2[1] = 0xE800 | ((((u32)dst - (u32)src2 - 4) & 0xFFF) >> 1);
void getfOpen(void *pos, u32 size, u32 *off){
//Calculate fOpen
u32 p9addr = *(u32*)(memsearch(pos, "ess9", size, 4) + 0xC);
u32 p9off = (u32)(memsearch(pos, "code", size, 4) + 0x1FF);
unsigned char pattern[] = {0xB0, 0x04, 0x98, 0x0D};
*off = (u32)memsearch(pos, pattern, size, 4) - 2 - p9off + p9addr;
}
void getFIRMWrite(void *pos, u32 size, u32 *off){
//Look for FIRM writing code
void *firmwrite = memsearch(pos, "exe:", size, 4);
unsigned char pattern[] = {0x00, 0x28, 0x01, 0xDA};
*off = (u32)memsearch(firmwrite - 0x100, pattern, 0x100, 4);
} }

View File

@@ -1,29 +1,62 @@
/* /*
* patches.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
#ifndef PATCHES_INC
#define PATCHES_INC #pragma once
#include "types.h" #include "types.h"
/************************************************** typedef struct patchData {
* Patches u32 offset[2];
**************************************************/ union {
u8 mpu[0x2C]; u8 type0[8];
u8 nandRedir[0x08]; u16 type1;
u8 sigPat1[2]; } patch;
u8 sigPat2[4]; u32 type;
u8 FIRMblock[4]; } patchData;
u8 emuInstr[5];
/************************************************** typedef struct __attribute__((packed))
* Functions {
**************************************************/ char magic[4];
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2);
void getReboot(void *pos, u32 size, u32 *off); u8 versionMajor;
void getfOpen(void *pos, u32 size, u32 *off); u8 versionMinor;
void getFIRMWrite(void *pos, u32 size, u32 *off); u8 versionBuild;
u8 flags;
#endif u32 commitHash;
u32 config;
} CFWInfo;
extern bool isN3DS;
extern u32 config;
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
void patchSignatureChecks(u8 *pos, u32 size);
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
void patchFirmWrites(u8 *pos, u32 size);
void patchFirmWriteSafe(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size);
void implementSvcGetCFWInfo(u8 *pos, u32 size);
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
void patchTwlBg(u8 *pos);

166
source/pin.c Normal file
View File

@@ -0,0 +1,166 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* pin.c
* Code to manage pin locking for 3ds. By reworks.
*/
#include "draw.h"
#include "screen.h"
#include "utils.h"
#include "memory.h"
#include "buttons.h"
#include "fs.h"
#include "pin.h"
#include "crypto.h"
bool readPin(PINData *out)
{
u8 __attribute__((aligned(4))) zeroes[16] = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
if(memcmp(out->magic, "PINF", 4) != 0) return false;
computePINHash(tmp, zeroes, 1);
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
}
static inline char PINKeyToLetter(u32 pressed)
{
const char keys[] = "AB--------XY";
u32 i;
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
return keys[31 - i];
}
void newPin(void)
{
clearScreens();
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
// Set the default value as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
u32 cnt = 0;
int charDrawPos = 20 * SPACING_X;
while(cnt < PIN_LENGTH)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
pressed &= PIN_BUTTONS & ~BUTTON_START;
if(!pressed) continue;
char key = PINKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; // add character to password.
// visualize character on screen.
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
}
PINData pin = {0};
u8 __attribute__((aligned(4))) tmp[32] = {0};
u8 __attribute__((aligned(4))) zeroes[16] = {0};
memcpy(pin.magic, "PINF", 4);
pin.formatVersionMajor = 1;
pin.formatVersionMinor = 0;
computePINHash(tmp, zeroes, 1);
memcpy(pin.testHash, tmp, 32);
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
memcpy(pin.hash, tmp, 32);
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
while(HID_PAD & PIN_BUTTONS);
}
void verifyPin(PINData *in)
{
initScreens();
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
// Set the default characters as 0x00 so we can check if there are any unentered characters.
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
u32 cnt = 0;
bool unlock = false;
int charDrawPos = 5 * SPACING_X;
while(!unlock)
{
u32 pressed;
do
{
pressed = waitInput();
}
while(!(pressed & PIN_BUTTONS));
if(pressed & BUTTON_START) mcuPowerOff();
pressed &= PIN_BUTTONS & ~BUTTON_START;
if(!pressed) continue;
char key = PINKeyToLetter(pressed);
enteredPassword[cnt++] = (u8)key; // add character to password.
// visualize character on screen.
drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
charDrawPos += 2 * SPACING_X;
if(cnt >= PIN_LENGTH)
{
u8 __attribute__((aligned(4))) tmp[32] = {0};
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
unlock = memcmp(in->hash, tmp, 32) == 0;
if(!unlock)
{
charDrawPos = 5 * SPACING_X;
cnt = 0;
clearScreens();
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
}
}
}
}

46
source/pin.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* pin.h
*
* Code to manage pin locking for 3ds. By reworks.
*/
#pragma once
#include "types.h"
#define PIN_LENGTH 4
typedef struct __attribute__((packed))
{
char magic[4];
u16 formatVersionMajor, formatVersionMinor;
u8 testHash[32];
u8 hash[32];
} PINData;
bool readPin(PINData* out);
void newPin(void);
void verifyPin(PINData *in);

259
source/screen.c Normal file
View File

@@ -0,0 +1,259 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#include "screen.h"
#include "config.h"
#include "memory.h"
#include "cache.h"
#include "draw.h"
#include "i2c.h"
vu32 *const arm11Entry = (vu32 *)0x1FFFFFF8;
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
void __attribute__((naked)) arm11Stub(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Wait for the entry to be set
while(*arm11Entry == ARM11_STUB_ADDRESS);
//Jump to it
((void (*)())*arm11Entry)();
}
static void invokeArm11Function(void (*func)())
{
static bool hasCopiedStub = false;
if(!hasCopiedStub)
{
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
hasCopiedStub = true;
}
*arm11Entry = (u32)func;
while(*arm11Entry);
*arm11Entry = ARM11_STUB_ADDRESS;
}
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Shutdown LCDs
*(vu32 *)0x10202A44 = 0;
*(vu32 *)0x10202244 = 0;
*(vu32 *)0x10202014 = 0;
WAIT_FOR_ARM9();
}
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
}
void updateBrightness(u32 brightnessIndex)
{
static u32 brightnessLevel;
brightnessLevel = brightness[brightnessIndex];
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Change brightness
*(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = brightnessLevel;
WAIT_FOR_ARM9();
}
flushDCacheRange(&brightnessLevel, 4);
invokeArm11Function(ARM11);
}
void clearScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Setting up two simultaneous memory fills using the GPU
vu32 *REGs_PSC0 = (vu32 *)0x10400010;
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
vu32 *REGs_PSC1 = (vu32 *)0x10400020;
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
REGs_PSC1[1] = (u32)(fb->bottom + 0x38400) >> 3; //End address
REGs_PSC1[2] = 0; //Fill value
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
if(fb->top_right != fb->top_left)
{
REGs_PSC0[0] = (u32)fb->top_right >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_right + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
while(!(REGs_PSC0[3] & 2));
}
WAIT_FOR_ARM9();
}
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
}
void initScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
u32 brightnessLevel = brightness[MULTICONFIG(0)];
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightnessLevel;
*(vu32 *)0x10202A40 = brightnessLevel;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen
*(vu32 *)0x10400400 = 0x000001c2;
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers
fb->top_left = (u8 *)0x18300000;
fb->top_right = (u8 *)0x18300000;
fb->bottom = (u8 *)0x18346500;
WAIT_FOR_ARM9();
}
if(PDN_GPU_CNT == 1)
{
flushDCacheRange(&config, 4);
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
clearScreens();
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
else
{
clearScreens();
updateBrightness(MULTICONFIG(0));
}
}

44
source/screen.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
/*
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi.
*/
#pragma once
#include "types.h"
#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
static volatile struct fb {
u8 *top_left;
u8 *top_right;
u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00;
void deinitScreens(void);
void updateBrightness(u32 brightnessIndex);
void clearScreens(void);
void initScreens(void);

View File

@@ -1,27 +1,70 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
@ Thanks to the numerous people who took part in writing this file
.section .text.start .section .text.start
.align 4 .align 4
.global _start .global _start
_start: _start:
b start
.global launchedFirmTIDLow
launchedFirmTIDLow:
.hword 0, 0, 0, 0, 0, 0, 0, 0
start:
@ Change the stack pointer @ Change the stack pointer
mov sp, #0x27000000 mov sp, #0x27000000
@ Give read/write access to all the memory regions @ Disable interrupts
ldr r5, =0x33333333 mrs r0, cpsr
mcr p15, 0, r5, c5, c0, 2 @ write data access orr r0, #0x1C0
mcr p15, 0, r5, c5, c0, 3 @ write instruction access msr cpsr_cx, r0
@ Sets MPU permissions and cache settings @ Disable caches / MPU
ldr r0, =0xFFFF001D @ ffff0000 32k mrc p15, 0, r0, c1, c0, 0 @ read control register
ldr r1, =0x01FF801D @ 01ff8000 32k bic r0, #(1<<12) @ - instruction cache disable
ldr r2, =0x08000027 @ 08000000 1M bic r0, #(1<<2) @ - data cache disable
ldr r3, =0x10000021 @ 10000000 128k bic r0, #(1<<0) @ - mpu disable
ldr r4, =0x10100025 @ 10100000 512k mcr p15, 0, r0, c1, c0, 0 @ write control register
ldr r5, =0x20000035 @ 20000000 128M
ldr r6, =0x1FF00027 @ 1FF00000 1M @ Flush caches
ldr r7, =0x1800002D @ 18000000 8M bl flushEntireDCache
mov r10, #0x25 bl flushEntireICache
mov r11, #0x25
mov r12, #0x25 @ Give read/write access to all the memory regions
ldr r0, =0x3333333
mcr p15, 0, r0, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
mov r7, #0
mov r8, #0x15
mcr p15, 0, r0, c6, c0, 0 mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0 mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0 mcr p15, 0, r2, c6, c2, 0
@@ -30,29 +73,21 @@ _start:
mcr p15, 0, r5, c6, c5, 0 mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0 mcr p15, 0, r7, c6, c7, 0
mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5 mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 4
mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5 mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5 mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
@ Enable caches @ Enable caches / MPU / ITCM
mrc p15, 0, r4, c1, c0, 0 @ read control register mrc p15, 0, r0, c1, c0, 0 @ read control register
orr r4, r4, #(1<<12) @ - instruction cache enable orr r0, r0, #(1<<18) @ - ITCM enable
orr r4, r4, #(1<<2) @ - data cache enable orr r0, r0, #(1<<12) @ - instruction cache enable
orr r4, r4, #(1<<0) @ - mpu enable orr r0, r0, #(1<<2) @ - data cache enable
mcr p15, 0, r4, c1, c0, 0 @ write control register orr r0, r0, #(1<<0) @ - mpu enable
mcr p15, 0, r0, c1, c0, 0 @ write control register
@ Flush caches @ Fix mounting of SDMC
mov r5, #0 ldr r0, =0x10000020
mcr p15, 0, r5, c7, c5, 0 @ flush I-cache mov r1, #0x340
mcr p15, 0, r5, c7, c6, 0 @ flush D-cache str r1, [r0]
mcr p15, 0, r5, c7, c10, 4 @ drain write buffer
@ Fixes mounting of SDMC b main
ldr r0, =0x10000020
mov r1, #0x340
str r1, [r0]
bl main
.die:
b .die

View File

@@ -1,37 +1,60 @@
/* /*
* types.h * This file is part of Luma3DS
* by Reisyukaku * Copyright (C) 2016 Aurora Wright, TuxSH
* Copyright (c) 2015 All Rights Reserved *
* 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.
*/ */
#ifndef TYPES_INC
#define TYPES_INC #pragma once
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CFG_UNITINFO (*(vu8 *)0x10010010)
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
//Common data types //Common data types
typedef uint8_t u8; typedef uint8_t u8;
typedef uint16_t u16; typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;
typedef volatile u32 vu32;
typedef uint64_t u64; typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
//FIRM Header layout //Used by multiple files:
typedef struct firmSectionHeader { typedef enum FirmwareSource
u32 offset; {
u8 *address; FIRMWARE_SYSNAND = 0,
u32 size; FIRMWARE_EMUNAND = 1,
u32 procType; FIRMWARE_EMUNAND2 = 2
u8 hash[0x20]; } FirmwareSource;
} firmSectionHeader;
typedef struct firmHeader { typedef enum FirmwareType
u32 magic; {
u32 reserved1; NATIVE_FIRM = 0,
u8 *arm11Entry; TWL_FIRM = 1,
u8 *arm9Entry; AGB_FIRM = 2,
u8 reserved2[0x30]; SAFE_FIRM = 3
firmSectionHeader section[4]; } FirmwareType;
} firmHeader;
#endif

126
source/utils.c Normal file
View File

@@ -0,0 +1,126 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "utils.h"
#include "i2c.h"
#include "buttons.h"
#include "screen.h"
#include "draw.h"
#include "cache.h"
extern bool isFirmlaunch;
u32 waitInput(void)
{
u32 pressedKey = 0,
key;
//Wait for no keys to be pressed
while(HID_PAD);
do
{
//Wait for a key to be pressed
while(!HID_PAD);
key = HID_PAD;
//Make sure it's pressed
for(u32 i = 0x13000; i; i--)
{
if(key != HID_PAD) break;
if(i == 1) pressedKey = 1;
}
}
while(!pressedKey);
return key;
}
void mcuReboot(void)
{
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(true);
}
void mcuPowerOff(void)
{
if(!isFirmlaunch && PDN_GPU_CNT != 1) clearScreens();
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
while(true);
}
//TODO: add support for TIMER IRQ
static inline void startChrono(u64 initialTicks)
{
//Based on a NATIVE_FIRM disassembly
REG_TIMER_CNT(0) = 0; //67MHz
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = (u16)(initialTicks >> (16 * i));
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
}
static inline void stopChrono(void)
{
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
}
void chrono(u32 seconds)
{
startChrono(0);
u64 startingTicks = 0;
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
u64 res;
do
{
res = 0;
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
}
while(res - startingTicks < seconds * TICKS_PER_SEC);
stopChrono();
}
void error(const char *message)
{
initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED);
int posY = drawString(message, 10, 30, COLOR_WHITE);
drawString("Press any button to shutdown", 10, posY + 2 * SPACING_Y, COLOR_WHITE);
waitInput();
mcuPowerOff();
}

35
source/utils.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
#define TICKS_PER_SEC 67027964ULL
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
u32 waitInput(void);
void mcuReboot(void);
void mcuPowerOff(void);
void chrono(u32 seconds);
void error(const char *message);