Compare commits

...

182 Commits

Author SHA1 Message Date
Aurora
1182d3a627 Fix #1050 2018-03-23 02:49:16 +01:00
TuxSH
938cb6492f Revert "Revert "Switched from mapping target process memory to svcReadProcessMemory & svcWriteProcessMemory functions.""
This reverts commit 1fd689f5da.
2018-03-20 01:11:49 +01:00
TuxSH
fed62855cb Merge pull request #1000 from duckbill007/master
Gateshark cheats support
2018-03-20 01:00:25 +01:00
Mikaela Szekely
4f54596658 Implement #940 (#1043)
Thanks @Qyriad ^^
2018-03-04 00:45:47 +01:00
Aurora Wright
0b41ed04d5 Simplify loadNintendoFirm after the previous commit 2018-02-09 05:09:43 +01:00
Aurora Wright
9509a86998 Force using the external FIRM if CTRNAND couldn't be mounted or the CTRNAND FIRM has issues 2018-02-05 03:47:43 +01:00
Duckbill
6d4d80a798 Merge remote-tracking branch 'upstream/master' 2018-01-19 17:38:57 +03:00
TuxSH
76d274cfe2 getmemregions: userland never exceeds 0x40000000 2018-01-19 01:42:53 +01:00
TuxSH
ccf13be964 Merge pull request #1010 from Nanquitas/input-redirection-sockupdate
InputRedirection: check service existence instead of using OpenProcessByName
2018-01-19 01:30:15 +01:00
TuxSH
e36b27ccf0 Merge pull request #1012 from Nanquitas/rosalina-freeze-fix
Rosalina: fix freeze when attempting to open Rosalina before the syst…
2018-01-19 01:29:58 +01:00
TuxSH
34c80ad476 Merge pull request #1009 from Nanquitas/gdb-list-memregion
gdb: new getmemregions command
2018-01-19 01:28:53 +01:00
TuxSH
97ae106d8e Merge pull request #1011 from Nanquitas/patch-2
sock_util: remove unneeded check
2018-01-19 01:28:08 +01:00
Nanquitas
7cb74b74d7 Rosalina: fix freeze when attempting to open Rosalina before the system finished to boot 2018-01-18 23:39:47 +01:00
Nanquitas
337205eb08 sock_util: remove unneeded check
We loop while (server_sockfd == -1) so it's safe to assume that (server_sockfd != -1) once out of the loop.
2018-01-18 22:57:46 +01:00
Nanquitas
f36977017b InputRedirection: check service existence instead of using OpenProcessByName 2018-01-18 20:44:54 +01:00
Nanquitas
e40b547bb6 gdb: new getmemregions command 2018-01-18 17:23:43 +01:00
Duckbill
1fd689f5da Revert "Switched from mapping target process memory to svcReadProcessMemory & svcWriteProcessMemory functions."
This reverts commit c5c8dca14c.
2018-01-16 09:54:55 +03:00
Duckbill
c5c8dca14c Switched from mapping target process memory to svcReadProcessMemory & svcWriteProcessMemory functions. 2018-01-15 21:29:05 +03:00
TuxSH
11f820efa7 Check service existence before GetServiceHandle 2018-01-15 02:52:50 +01:00
TuxSH
9074688491 Make srvGetServiceHandle non-blocking if service port is full in all cases 2018-01-15 02:27:07 +01:00
Duckbill
1de27c54f1 Fix range checks 2018-01-13 16:02:54 +03:00
Duckbill
3e67e64faa Fixes after review on github 2018-01-13 13:51:28 +03:00
TuxSH
553f8d2533 Remove lto for sysmodules 2018-01-12 11:20:17 +01:00
Duckbill
ec7ae35da1 Fixes for masked 16-bit cheat opcodes, based on existing cheats. 2018-01-12 10:46:50 +03:00
Duckbill
7e8da0d236 Possible out of bounds fix 2018-01-10 09:53:36 +03:00
Duckbill
b3e6561072 Merge remote-tracking branch 'upstream/master' 2018-01-06 12:29:08 +03:00
Aurora Wright
41f32ed983 Remove the need for hardcoding the horizontal positions for the "x"s in multiple choice options 2018-01-05 19:38:58 +01:00
TuxSH
bbadf840ef struct fb shouldn't be packed 2018-01-04 22:12:31 +01:00
TuxSH
acc50aae46 Merge branch 'master' of github.com:AuroraWright/Luma3DS 2018-01-04 18:41:14 +01:00
TuxSH
6a68a77973 Rewrite the ARM9 exception handlers, ...
- Fix patchArm9ExceptionHandlersInstall for older versions

- Fix some bugs in the ARM11 exception handlers

- Other, minor, changes
2018-01-04 18:40:11 +01:00
Duckbill
0f4d66dd61 Try to load cheats if there aren't any on every open of cheats menu. 2018-01-03 11:48:10 +03:00
Duckbill
d28642d2c3 More range checks and separate code and heap allocation 2018-01-03 00:27:44 +03:00
Duckbill
ca4685cc42 Range checks added 2018-01-02 14:23:45 +03:00
Aurora
522f10582d Merge pull request #995 from joel16/master
Update MCU::HWC functions with latest changes from ctrulib
2018-01-01 18:07:32 +01:00
Joel16
239d113177 Update mcu functions with changes from ctrulib 2018-01-01 11:05:22 -06:00
Duckbill
fd80294bf2 Fix buffer overflow in case of very long cheats.txt file 2017-12-31 11:26:18 +03:00
Duckbill
b379d83469 Merge remote-tracking branch 'upstream/master' 2017-12-31 11:16:44 +03:00
Aurora
27f352fdf1 Merge pull request #991 from Qyriad/master
Implement #989: Add configurable splash duration
2017-12-29 05:08:22 +01:00
Mikaela RJ Szekely
bfec874a7c Add colon in option that I forgot 2017-12-28 22:02:06 -05:00
Mikaela RJ Szekely
93561003e8 Implement #989: Add configurable splash duration 2017-12-28 21:50:06 -05:00
TuxSH
1572bfd989 [sm] Fix process unregistering logic bug (fixes #984)
In this case pm+sm were supposed to automatically unregister ro's services (the kernel can close a dying process's handle automatically). Not doing this apparently induced a reference leak of DevMenu's as a process, preventing it to be destroyed and the memory allocation reslimit counter to be updated by KProcess's destructor accordingly.
2017-12-27 19:30:57 +01:00
Duckbill
cb945612a3 Remove ast empty cheat from list 2017-12-25 14:16:57 +03:00
Duckbill
1b440f7f3b Skip empty cheats 2017-12-25 13:57:20 +03:00
Duckbill
78791f7b66 Paging fixes 2017-12-25 13:45:09 +03:00
Duckbill
5def0c18e2 Cheat file format changed from binary to plaintext 2017-12-22 14:46:46 +03:00
Duckbill
0e67b0f026 Moved key combo calculation to loading cheat phase 2017-12-22 12:39:09 +03:00
Duckbill
8052946517 Cheats array repleced by continous buffer 2017-12-22 12:17:45 +03:00
Duckbill
b6d6cc9750 Cheat implementations 2017-12-21 20:14:04 +03:00
TuxSH
2a840f2c79 Minor date/time conversion loop style fixes 2017-12-19 02:32:51 +01:00
TuxSH
4eaf791849 Merge pull request #937 from Hayleia/timestamped-screenshots
screenshots use timestamps as name
2017-12-19 02:15:07 +01:00
Aurora Wright
be0f50b19c Disable poweroff when shell closed on NTRboothax altogether to prevent issues with unstable magnets 2017-12-18 21:02:41 +01:00
Aurora Wright
f30b7b9fb3 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-12-18 20:56:45 +01:00
Aurora Wright
6a0f332e3c Shutdown when waiting for button presses if the shell is closed, except when coming from a NTRboothax boot 2017-12-18 20:56:32 +01:00
TuxSH
16530d3a52 Merge pull request #972 from LiquidFenrir/ramviewer-fix
fix mistake, processes viewed were attached even if debugger was off
2017-12-18 07:13:13 +01:00
Aurora Wright
20af9c6750 Fix issue reported in
f27cdb4543\#commitcomment-24611141, simplify 56e54cd110
2017-12-18 04:27:11 +01:00
LiquidFenrir
fee9f6b427 forgot to return, made processes viewed attached even though the debugger wasnt enabled 2017-12-17 19:31:05 +01:00
TuxSH
57d03d6333 Merge pull request #916 from LiquidFenrir/ramviewer-fix
Several ramviewer improvements
2017-12-17 03:31:36 +01:00
LiquidFenrir
0075fe2aa0 work with processes with code starting at 0x14000000 2017-12-16 19:26:55 +01:00
LiquidFenrir
d54417ac0a explicit casting 2017-12-16 19:26:27 +01:00
LiquidFenrir
648801d432 make pressing X accidentally twice less punitive 2017-12-16 04:30:40 +01:00
LiquidFenrir
2be2826b0b detect jumping address and change mode accordingly 2017-12-16 04:14:21 +01:00
LiquidFenrir
37a9fa1bf4 work again with heapless processes, and show wether you're currently viewing heap or code on screen (apart from the address) 2017-12-14 17:03:13 +01:00
LiquidFenrir
65af93c8ce other display for entering goto 2017-12-07 22:07:53 +01:00
LiquidFenrir
8353b84944 fix dump filename 2017-12-07 20:07:44 +01:00
LiquidFenrir
d6a89db495 make use of values defined in draw.h 2017-12-07 19:56:36 +01:00
LiquidFenrir
f156aa8cdb add dumper
mostly a copy of the screenshotting function/from #937
2017-12-07 19:53:44 +01:00
LiquidFenrir
f9adbcc9d9 fix same-name variables 2017-12-07 18:23:29 +01:00
TuxSH
cf8696ac70 Disable non-process memory access by default (see below), remove IDA 6.8 support...
The physical memory access "bit31" mapping (0--0x30000000 => 0x80000000--0xB0000000) as well as privileged (kernel) mappings confuse debugger clients like IDA's which interpret the value of the registers.
Access to those mappings can be toggled using "monitor toggleextmemaccess" instead (issue reported by @Nanquitas). Closes #943.

Additionally, support for the buggy IDA 6.8's buggy gdb client was removed. Please use IDA 7.0 or higher.

P.S: IDA 7.0 added client support for no-ack mode (Debugging options > Set specific options), which should be enabled to make debugging twice as smooth. "Use stepping support" should be unchecked.
2017-11-26 02:18:59 +01:00
Yuuki Hikari
9c5766f649 Merge pull request #945 from astronautlevel2/master
Switch to APT_ResetHardwareAsync() for reboot (Closes #831), fix #831
2017-11-23 20:46:01 -05:00
Alex Taber
c9701f93b9 Switch to APT_ResetHardwareAsync() for reboot (Closes #831) 2017-11-23 20:32:26 -05:00
Aurora Wright
56e54cd110 Fix https://github.com/AuroraWright/Luma3DS/issues/921 2017-11-22 19:03:39 +01:00
TuxSH
55836b48af Merge pull request #942 from Nanquitas/watchpoint-fix
Fix the impossibility to set a second watchpoint
2017-11-22 16:17:53 +01:00
Asuka Amari
09bfdb9ee1 removed unused variable 2017-11-22 07:03:00 +01:00
Nanquitas
1c2e8dec11 Fix the impossibility to set a second watchpoint 2017-11-22 03:37:23 +01:00
TuxSH
506b16db37 Fix watchpoints handling (huge thanks to @Nanquitas) 2017-11-22 01:24:35 +01:00
Asuka Amari
8f03234e58 screenshots now use timestamps as name
Instead of being called top_XXXX.bmp where XXXX means nothing,
screenshots are now called YYYY-MM-DD_HH-MM-SS.mmm_top.bmp (and same
idea for bot and top_right).

First obvious consequence, this is easier to manage in a file browser.
Now you have screenshots grouped by time, and you also have the 2 or 3
related screenshots (top, bot, top_right) close one to another.

Another consequence is that there is no need to go through existing
screenshots to find an unused number. Now osGetTime takes care of
everything. And going through files was a very time consuming process.
Now screenshots only need 4 (or 6 if 3D) seconds to be saved (instead of
40 seconds if you had 200 screenshots in your directory already).

Conflicts may happen when people change the date and time on their 3DS,
but that's why I even included milliseconds in the timestamp. People
don't set date and time everyday and they'd be unlucky to take a
screenshot at the exact time, milliseconds included, as another
screenshot right after setting the time one hour earlier...

Source for converting seconds since 1970 (or 1900...) to date and time:
https://stackoverflow.com/questions/21593692/
2017-11-18 16:37:35 +01:00
TuxSH
44b5e10323 Fix N3DS menu entry 2017-11-10 20:51:52 +01:00
LiquidFenrir
48303604b0 show address instead of offset when jumping 2017-11-05 06:56:54 +01:00
LiquidFenrir
ab2ddbc2ee fix visible blank
if jumping too close to the end, the cursor won't be at the top to avoid the blank
2017-11-05 06:48:56 +01:00
LiquidFenrir
9495bf30bf make jumping put the cursor at the top row
downside: when jumping near the end, a blank is visible
2017-11-05 06:30:41 +01:00
TuxSH
a4899a1bec Remove redundant variables in Makefile 2017-11-03 19:03:17 +01:00
LiquidFenrir
882c6cf0d4 show the "main" address to distinguish between heap and code 2017-11-03 02:19:15 +01:00
LiquidFenrir
a5e18c82d1 reset scrolling when changing modes to avoid problems when the sizes dont match 2017-11-03 02:15:28 +01:00
TuxSH
22a8661fe1 Always patch FS and P9, remove SM service checks 2017-11-02 21:52:14 +01:00
TuxSH
8258a98647 Integrate 3ds_pxi and 3ds_sm 2017-11-02 15:11:55 +01:00
LiquidFenrir
76dde0e6db Add ram viewer/editor (#877)
Huge thanks to @LiquidFenrir
2017-10-24 18:35:15 +02:00
Ian Burgwin
1a39cb27e4 fix discord invite link 2017-10-14 10:10:03 -07:00
Aurora Wright
95d2d0a6bd Update makefile 2017-10-12 20:56:47 +02:00
Aurora Wright
98d4345858 Remove unneeded check 2017-10-07 23:04:55 +02:00
Aurora Wright
1e4431dcc9 Fix ARM9 exceptions displaying ARM11-specific info 2017-10-07 20:59:21 +02:00
Aurora Wright
348b175994 Fix some fault statuses overlapping to a new line 2017-10-05 19:55:21 +02:00
Aurora Wright
76f057dafb Remove friends patch as it's useless 2017-10-05 18:45:06 +02:00
Aurora Wright
188400c5a9 Use ctrulib functions for mcu/battery level 2017-10-05 18:41:11 +02:00
Aurora
a74d9c6d3e Merge pull request #878 from Margen67/master
Update README.md
2017-10-03 01:19:26 +02:00
Margen67
f8bcfb2f58 Update README.md
Add armips buildbot link.
Other minor changes.
2017-09-26 14:44:14 -07:00
TuxSH
d63fc2bc82 Fix latest commit 2017-09-24 19:31:38 +02:00
TuxSH
8e31784996 Fix thumb breakpoint handling 2017-09-24 17:58:23 +02:00
Aurora Wright
f27cdb4543 Also fix RBGA4 (untested) 2017-09-23 22:34:28 +02:00
Aurora
a39adc8ac1 Merge pull request #869 from Streetwalrus/pxfmt
Fix RGB5_A1 conversion
2017-09-23 22:27:24 +02:00
Dan Elkouby
97bef66018 Fix RGB5_A1 conversion 2017-09-23 15:01:11 +03:00
Aurora Wright
bb5518b0f6 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-09-22 18:05:10 +02:00
Aurora Wright
ac73a96ce2 Set default firmSource for CTRNAND mounting in crypto.c, move CTRNAND mounting for SD mode to firm.c 2017-09-22 18:05:03 +02:00
Ian Burgwin
7075004e58 Merge pull request #866 from Margen67/master
Update ISSUE_TEMPLATE.md
2017-09-21 14:04:38 -07:00
Margen67
ddf8ba5116 Update ISSUE_TEMPLATE.md 2017-09-21 14:02:09 -07:00
Aurora Wright
f46773ba64 Stub isTitleAllowed 2017-09-20 01:36:02 +02:00
Aurora Wright
f67d333457 Update fpdver 2017-09-19 14:46:42 +02:00
Aurora Wright
4116c1e00f Update FIRM loading magic, only deinit LCDs if they are inited, fix ntrboot naming 2017-09-07 05:24:43 +02:00
Aurora Wright
bc1aa15dd7 Add more checks, make the emuNAND SD check only occur when emuNAND is being booted 2017-08-28 14:46:18 +02:00
Aurora Wright
ecd27f7eaa Fix diskio indentation 2017-08-28 02:54:56 +02:00
Aurora Wright
618ce671ac Fix previous commit, deinit screens on ARM9 exception, add check for write protect switch on writing operations 2017-08-28 02:43:12 +02:00
Hikari-chin
2a6a655804 Error if emuNAND is booted while the SD card is write protected 2017-08-27 16:20:17 -04:00
Aurora Wright
33436ae2a6 Fix derp with previous commit 2017-08-27 16:24:04 +02:00
Aurora Wright
9f2b66ac51 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-08-27 16:20:52 +02:00
Aurora Wright
df93e4797e Refactor boot mode/firmlaunch detection, fix firmlaunch from FIRM boots 2017-08-27 16:20:41 +02:00
Aurora Wright
538d1dec77 Minor style stuff 2017-08-21 19:33:31 +02:00
TuxSH
2492c8273a Fix exception display 2017-08-21 19:26:17 +02:00
Aurora Wright
d358df48a6 Wait for ntrboot buttons not to be held 2017-08-20 18:23:50 +02:00
Aurora Wright
f619dafff1 Added displaying boot source and loader on the bottom screen in the config 2017-08-20 17:00:47 +02:00
Aurora Wright
0419fc4e30 Reinstate ntrboot display in config 2017-08-20 16:16:20 +02:00
Aurora Wright
13317b9548 Change ntrboot behavior, turn Luma into a chainloader when used as ntrboot FIRM as it can not be functional, disable FIRM protection when ran from ntrboot B9S 2017-08-20 16:08:54 +02:00
Aurora Wright
18db70a669 Minor style stuff 2017-08-19 02:54:38 +02:00
TuxSH
f79923814d Detect NTRCARD and FIRM1 boot sources properly...
Always display the configuration menu if booted from NTRCARD (because it's painful to get to otherwise -- even if b9s has a 2s delay), with the mention "Booted from NTRCARD" in the title.
2017-08-19 01:40:55 +02:00
Aurora Wright
c92de03a5f Always erase exception dump in memory 2017-08-17 17:38:42 +02:00
Aurora Wright
3f356da879 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-08-17 17:33:37 +02:00
Aurora Wright
9efac01c86 Fix derp 2017-08-17 17:33:18 +02:00
TuxSH
ca2622af7c Fix #778 2017-08-16 23:46:36 +02:00
Aurora Wright
aa8e0bda8c Update FatFs to R0.13 2017-08-16 19:37:39 +02:00
TuxSH
c79f11ee99 Change exception dump parser directory structure 2017-08-16 19:23:04 +02:00
Aurora Wright
04d0770b90 Add missing info for data aborts in the exception parser and turn it into a pip module 2017-08-16 18:59:12 +02:00
Aurora Wright
fbf8a1b6d9 Minor code syntax stuff 2017-08-16 18:04:22 +02:00
Aurora Wright
a3cb6a622d Merge https://github.com/AuroraWright/Luma3DS/pull/793 , clarify the exception dumps' paths 2017-08-16 16:55:07 +02:00
Aurora Wright
0790a3ceb3 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-08-16 15:50:06 +02:00
Aurora Wright
4fa12f90fc Fix derp 2017-08-16 15:49:57 +02:00
TuxSH
d5d56e7634 Merge pull request #790 from WinterMute/windows-path-fix
Don't fix already transformed $DEVKITARM variable
2017-08-15 15:20:27 +02:00
TuxSH
a964089df4 Merge pull request #792 from Nanquitas/master
Exceptions: display more infos on screen (status, far, access type)
2017-08-15 15:20:17 +02:00
Dave Murphy
5fd5b4da89 Don't fix already transformed $DEVKITARM variable 2017-08-15 14:15:34 +01:00
Hikari-chin
322a7050aa Fix #791 2017-08-15 09:01:48 -04:00
Nanquitas
b7f4ac02c8 Exceptions: display more infos on screen (status, far, access type) 2017-08-15 14:09:14 +02:00
TuxSH
009f61a8b6 Merge pull request #787 from Nanquitas/master
exception_parser.py: display the fault status source
2017-08-15 02:44:18 +02:00
Nanquitas
26d0cafb39 exception_parser.py: display the fault status source 2017-08-15 00:51:20 +02:00
TuxSH
bd1d4a77fe Merge pull request #783 from Nanquitas/patch-1
Watchpoints: fix read DSCR to enable MonitorMode
2017-08-14 19:04:15 +02:00
Nanquitas
f235bc83a8 Watchpoints: fix read DSCR to enable MonitorMode 2017-08-14 16:10:50 +02:00
Aurora Wright
9c6b540905 Do not hardcode FBs in ARM11, do not set FBs twice on screen init 2017-08-13 17:36:31 +02:00
TuxSH
d2e911a58e Merge pull request #781 from profi200/master
Revert 9273a88d and make it not freeze the GPU/LCD hardware.
2017-08-13 16:00:45 +02:00
TuxSH
9344a7b434 Fix default FB addresses 2017-08-13 16:00:35 +02:00
profi200
cd194fa5b2 Revert 9273a88d and make it not freeze the GPU/LCD hardware. 2017-08-13 14:50:14 +02:00
Aurora Wright
49c0ab65df Check r0 and r1 too for firm0 detection 2017-08-11 23:54:28 +02:00
Aurora Wright
8f9c1305e4 Reinstate unsupported loader error 2017-08-11 23:48:32 +02:00
TuxSH
d4193ec11d Attempt to detect booting from firm 2017-08-11 23:33:21 +02:00
TuxSH
6b9b0472bc Merge pull request #775 from LiquidFenrir/nwmcheck
Add a warning when nwm isn't running
2017-08-11 23:00:07 +02:00
LiquidFenrir
7e74258363 check if nwm is running to fix https://github.com/AuroraWright/Luma3DS/issues/774 2017-08-11 04:29:38 +02:00
Aurora Wright
f6483ec602 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-08-07 21:20:18 +02:00
Aurora Wright
36c1da1d61 Add mention of exheaders in the Enable game patching description 2017-08-07 21:20:08 +02:00
Stary 2001
6bcb1f8679 Merge pull request #763 from Streetwalrus/ir-title
Fix input redirection title index in the menu
2017-08-06 22:15:21 +01:00
Dan Elkouby
62932a9639 Fix input redirection title index in the menu
This option is the third, not the fourth, and toggling it will override
the "save settings" option's title instead.
2017-08-06 23:56:00 +03:00
Hikari-chin
a4629e4b65 Cleaned up and rearranged the Rosalina menu in preparation for future features 2017-08-01 17:38:48 +02:00
Aurora Wright
a0c2b43b34 Implement loading of exheaders from SD/CTRNAND (must be called luma/titles/TITLEID/exheader.bin), thanks to @HiddenRambler! 2017-08-01 17:38:23 +02:00
TuxSH
3907c46980 Follow ARM's documentation on hw watchpoints to the letter 2017-07-20 00:56:08 +02:00
TuxSH
7e7ab124a3 Log "logged" errdisp messages in /luma/errdisp.txt, fixes #707 2017-07-19 00:59:47 +02:00
TuxSH
cfc6cf24bf Some kext refactoring 2017-07-16 18:58:20 +02:00
TuxSH
46e9cb6b23 Fix fallthrough bug 2017-07-16 13:29:02 +02:00
TuxSH
ba14efe1f4 Suppress future -Wimplicit-fallthrough=3 warnings 2017-07-15 00:41:42 +02:00
TuxSH
3d8f62d38f Fix MaxCpuTime for 3dsx 2017-07-09 22:14:00 +02:00
Hikari-chin
3edaf0af64 Whoops 2017-07-09 14:36:06 -04:00
Aurora Wright
9273a88db7 It seems FB setup needs to be done first 2017-07-09 19:21:12 +02:00
Aurora Wright
37ba2c15de Reinstate framebuffer setup on initScreens to allow old Luma to be chainloaded if FB address changes in b9s/new Luma, remove useless clearScreens for the alternate FBs after the first init 2017-07-09 19:06:42 +02:00
Aurora Wright
557f2057f7 Fix spacing 2017-07-06 18:09:18 +02:00
Aurora Wright
6b5cc93780 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-07-06 17:29:43 +02:00
Aurora Wright
9760191af8 Fix conflict between emunand selection and payload booting when "Autoboot EmuNAND" is checked, you now need to press L + DPad to boot payloads if that option is checked 2017-07-06 17:29:38 +02:00
TuxSH
8845e4dd20 Merge pull request #704 from Hikari-chin/master
LED toggle switch in Rosalina's misc menu + updated README
2017-07-05 19:26:56 +02:00
Yuuki Hikari
8cf823f548 Update README.md 2017-07-05 02:13:03 -04:00
Hikari-chin
2538769f3a Added LED toggling from the Rosalina misc. menu 2017-07-04 23:50:40 -04:00
Aurora Wright
89fca38807 Merge master into local branch 2017-07-05 01:37:36 +02:00
Aurora Wright
dcc0eed69c Fix LayeredFS for games like Pokemon Art Academy which mistakenly use two forward slashes after the mountpoint 2017-07-05 01:31:04 +02:00
Yuuki Hikari
817475257e Merge pull request #700 from LiquidFenrir/wifi-toggle
Add wireless toggling in rosalina
2017-07-04 15:09:16 -04:00
LiquidFenrir
f2861058ba add wireless toggling in rosalina
https://github.com/AuroraWright/Luma3DS/issues/619#issuecomment-309239178

ligne 353: CFG11_WIFICNT, nothing includes it in rosalina so I hardcoded it here
ligne 363: could also use svc 0x5A (SetWifiEnabled) but not sure how
2017-07-04 18:35:55 +02:00
TuxSH
5d2a7315d5 Fix SetWifiEnabled 2017-07-03 19:28:34 +02:00
TuxSH
1520ab7555 Update ISSUE_TEMPLATE.md
7.1 => 8.1
2017-07-02 22:52:49 +02:00
Aurora Wright
d4d0fbd73b Re-add dir_build variable 2017-07-02 00:46:57 +02:00
Aurora Wright
ddb8e98e95 Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2017-07-02 00:44:29 +02:00
Aurora Wright
fd69b4169f Use GNU/BSD agnostic syntax instead of detecting the OS (thanks @smartperson) 2017-07-02 00:44:14 +02:00
TuxSH
b48e0b5c5b Update ISSUE_TEMPLATE.md 2017-06-30 23:52:44 +02:00
146 changed files with 23628 additions and 2677 deletions

View File

@@ -1,11 +1,13 @@
<!-- <!--
-- THIS IS NOT A SUPPORT FORUM! For support go here: -- THIS IS NOT A SUPPORT FORUM! For support go here:
-- Nintendo Hacking: https://discord.gg/MjzatM8y -- Nintendo Homebrew: https://discord.gg/MjzatM8
--
-- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752
-- --
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue. -- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
-- --
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting -- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting
-- If you're using an emu/redNAND anything related to that must also be installed to sysNAND. -- If you're using an emu/redNAND try installing anything on it to sysNAND.
-- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s). -- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
-- --
-- Luma updaters that don't support Boot9Strap/Sighax won't work. -- Luma updaters that don't support Boot9Strap/Sighax won't work.
@@ -18,7 +20,7 @@
**SysNAND version (+emu/redNAND version if applicable):** **SysNAND version (+emu/redNAND version if applicable):**
[e.g. 11.4.0-37U SysNAND, 11.4.0-37J EmuNAND] [e.g. 11.6.0-39U SysNAND, 11.6.0-39J EmuNAND]
**Entrypoint (How/what you're using to boot Luma3DS):** **Entrypoint (How/what you're using to boot Luma3DS):**
@@ -26,7 +28,7 @@
**Luma3DS version:** **Luma3DS version:**
[e.g. 7.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e] [e.g. 8.1.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
<!--You can check which version you're on in System Settings. It will be on the bottom right of the top screen.--> <!--You can check which version you're on in System Settings. It will be on the bottom right of the top screen.-->
@@ -51,9 +53,7 @@ Use EmuNAND FIRM if booting with R: ( )
Enable loading external FIRMs and modules: ( ) Enable loading external FIRMs and modules: ( )
<!--Firmware (.bin) files are not required by Luma, or NTR CFW anymore. <!--Firmware (.bin) files are not required by Luma, or NTR CFW anymore.
-- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card and disabling this option.--> -- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card or /rw/luma on CTRNAND and disabling this option.-->
Use custom path: ( )
Enable game patching: ( ) Enable game patching: ( )
@@ -65,6 +65,8 @@ Patch ARM9 access: ( )
Set developer UNITINFO: ( ) Set developer UNITINFO: ( )
Disable ARM11 exception handlers: ( )
-- --
@@ -83,6 +85,6 @@ Set developer UNITINFO: ( )
**Dump file:** **Dump file:**
<!--If the issue leads to a crash you can generate a crash dump by checking the "Enable exception handlers" option. <!--If the issue leads to a crash you must uncheck the "Disable ARM11 exception handlers" option.
-- The error message will tell you where the dump is. -- The error message will tell you where the dump is.
-- Zip the dmp file and drag & drop it below.--> -- Zip the dmp file and drag & drop it below.-->

4
.gitignore vendored
View File

@@ -14,3 +14,7 @@ exceptions/arm11/build
*.elf *.elf
*.cxi *.cxi
.DS_Store .DS_Store
*.dmp
.project
.cproject
.settings

View File

@@ -10,13 +10,6 @@ endif
include $(DEVKITARM)/base_tools include $(DEVKITARM)/base_tools
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
size := stat -f%z
else
size := stat -c%s
endif
name := Luma3DS name := Luma3DS
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/') revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/')
version_major := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f1 -d.) version_major := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f1 -d.)
@@ -54,6 +47,8 @@ dir_k11_extension := k11_extension
dir_sysmodules := sysmodules dir_sysmodules := sysmodules
dir_loader := $(dir_sysmodules)/loader dir_loader := $(dir_sysmodules)/loader
dir_rosalina := $(dir_sysmodules)/rosalina dir_rosalina := $(dir_sysmodules)/rosalina
dir_sm := $(dir_sysmodules)/sm
dir_pxi := $(dir_sysmodules)/pxi
dir_build := build dir_build := build
dir_out := out dir_out := out
@@ -67,7 +62,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi $(dir_build)/sm.cxi $(dir_build)/pxi.cxi
define bin2o define bin2o
bin2s $< | $(AS) -o $(@) bin2s $< | $(AS) -o $(@)
@@ -90,6 +85,8 @@ clean:
@$(MAKE) -C $(dir_k11_extension) clean @$(MAKE) -C $(dir_k11_extension) clean
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_rosalina) clean @$(MAKE) -C $(dir_rosalina) clean
@$(MAKE) -C $(dir_sm) clean
@$(MAKE) -C $(dir_pxi) clean
@rm -rf $(dir_out) $(dir_build) @rm -rf $(dir_out) $(dir_build)
.PRECIOUS: $(dir_build)/%.bin .PRECIOUS: $(dir_build)/%.bin
@@ -100,10 +97,13 @@ clean:
.PHONY: $(dir_k11_extension) .PHONY: $(dir_k11_extension)
.PHONY: $(dir_loader) .PHONY: $(dir_loader)
.PHONY: $(dir_rosalina) .PHONY: $(dir_rosalina)
.PHONY: $(dir_sm)
.PHONY: $(dir_pxi)
$(dir_out)/$(name)$(revision).7z: all $(dir_out)/$(name)$(revision).7z: all
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py @[ -f "$@" ] || 7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser -xr!.DS_Store
$(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf $(dir_build)/k11_extension.bin $(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf $(dir_build)/k11_extension.bin
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@@ -132,6 +132,14 @@ $(dir_build)/rosalina.cxi: $(dir_rosalina)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@$(MAKE) -C $< @$(MAKE) -C $<
$(dir_build)/sm.cxi: $(dir_sm)
@mkdir -p "$(@D)"
@$(MAKE) -C $<
$(dir_build)/pxi.cxi: $(dir_pxi)
@mkdir -p "$(@D)"
@$(MAKE) -C $<
$(dir_build)/%.bin.o: $(dir_build)/%.bin $(dir_build)/%.bin.o: $(dir_build)/%.bin
@$(bin2o) @$(bin2o)
@@ -152,7 +160,7 @@ $(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configura
$(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\ $(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\
-DVERSION_BUILD="$(version_build)" -DISRELEASE="$(is_release)" -DCOMMIT_HASH="0x$(commit)" -DVERSION_BUILD="$(version_build)" -DISRELEASE="$(is_release)" -DCOMMIT_HASH="0x$(commit)"
$(dir_build)/firm.o: $(dir_build)/modules.bin $(dir_build)/firm.o: $(dir_build)/modules.bin
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell $(size) $(dir_build)/modules.bin)" $(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell wc -c $(dir_build)/modules.bin | tr -d [:space:][:alpha:][:punct:])"
$(dir_build)/bundled.h: $(bundled) $(dir_build)/bundled.h: $(bundled)
@$(foreach f, $(bundled),\ @$(foreach f, $(bundled),\

View File

@@ -15,9 +15,9 @@ Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Down+Sel
First you need to clone the repository with: `git clone https://github.com/AuroraWright/Luma3DS.git` First you need to clone the repository with: `git clone https://github.com/AuroraWright/Luma3DS.git`
To compile, you'll need [armips](https://github.com/Kingcom/armips) and a build of a recent commit of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. You'll also need to install [firmtool](https://github.com/TuxSH/firmtool), its README contains installation instructions. To compile, you'll need [armips](https://github.com/Kingcom/armips) and a build of a recent commit of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. You'll also need to install [firmtool](https://github.com/TuxSH/firmtool), its README contains installation instructions.
For now, you'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit. You'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit.
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!). Here are [Windows](https://buildbot.orphis.net/armips/) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!) and [makerom](https://github.com/Steveice10/buildtools/tree/master/3ds) (thanks @Steveice10!).
Finally just run `make` and everything should work! Run `make` and everything should work!
You can find the compiled files in the `out` folder. You can find the compiled files in the `out` folder.
--- ---

View File

@@ -11,6 +11,6 @@ SECTIONS
.data : ALIGN(4) { *(.data*); . = ALIGN(4); } .data : ALIGN(4) { *(.data*); . = ALIGN(4); }
.bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; } .bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; }
__stack_top__ = 0x1FFFF000; __stack_top__ = 0x1FFFE000;
. = ALIGN(4); . = ALIGN(4);
} }

View File

@@ -120,6 +120,16 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
*(vu32 *)0x10400584 = 0x10101 * i; *(vu32 *)0x10400584 = 0x10101 * i;
} }
static void setupFramebuffers(struct fb *fbs)
{
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
}
static void clearScreens(struct fb *fb) static void clearScreens(struct fb *fb)
{ {
//Setting up two simultaneous memory fills using the GPU //Setting up two simultaneous memory fills using the GPU
@@ -175,6 +185,9 @@ void main(void)
case INIT_SCREENS: case INIT_SCREENS:
initScreens(*(vu32 *)ARM11_PARAMETERS_ADDRESS, (struct fb *)(ARM11_PARAMETERS_ADDRESS + 4)); initScreens(*(vu32 *)ARM11_PARAMETERS_ADDRESS, (struct fb *)(ARM11_PARAMETERS_ADDRESS + 4));
break; break;
case SETUP_FRAMEBUFFERS:
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);
break;
case CLEAR_SCREENS: case CLEAR_SCREENS:
clearScreens((struct fb *)ARM11_PARAMETERS_ADDRESS); clearScreens((struct fb *)ARM11_PARAMETERS_ADDRESS);
break; break;

View File

@@ -50,11 +50,12 @@ struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; u8 *bottom;
} __attribute__((packed)); };
typedef enum typedef enum
{ {
INIT_SCREENS = 0, INIT_SCREENS = 0,
SETUP_FRAMEBUFFERS,
CLEAR_SCREENS, CLEAR_SCREENS,
SWAP_FRAMEBUFFERS, SWAP_FRAMEBUFFERS,
UPDATE_BRIGHTNESS, UPDATE_BRIGHTNESS,

View File

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

View File

@@ -42,4 +42,4 @@ struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; u8 *bottom;
} __attribute__((packed)); };

View File

@@ -13,8 +13,8 @@ dir_build := build
dir_out := ../../$(dir_build) dir_out := ../../$(dir_build)
ASFLAGS := -mcpu=arm946e-s ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -Os -ffast-math
LDFLAGS := -nostdlib LDFLAGS := -nostartfiles -Wl,--nmagic
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \

View File

@@ -4,7 +4,7 @@ OUTPUT_ARCH(arm)
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x01FF7FE0; . = 0x01FF8000;
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }

View File

@@ -43,8 +43,9 @@ typedef struct __attribute__((packed))
u32 additionalDataSize; u32 additionalDataSize;
} ExceptionDumpHeader; } ExceptionDumpHeader;
u32 readMPUConfig(u32 *regionSettings);
void FIQHandler(void); void FIQHandler(void);
void undefinedInstructionHandler(void); void undefinedInstructionHandler(void);
void dataAbortHandler(void); void dataAbortHandler(void);
void prefetchAbortHandler(void); void prefetchAbortHandler(void);
u32 safecpy(void *dst, const void *src, u32 len);

View File

@@ -22,92 +22,131 @@
@ or requiring that modified versions of such material be marked in @ or requiring that modified versions of such material be marked in
@ reasonable ways as different from the original version. @ reasonable ways as different from the original version.
.macro GEN_HANDLER name .macro GEN_USUAL_HANDLER name, index
.global \name \name\()Handler:
.type \name, %function ldr sp, =_regs
\name: stmia sp, {r0-r7}
ldr sp, =#0x02000000 @ We make the (full descending) stack point to the end of ITCM for our exception handlers.
@ It doesn't matter if we're overwriting stuff here, since we're going to reboot.
stmfd sp!, {r0-r7} @ FIQ has its own r8-r14 regs mov r0, #\index
ldr r1, =\@ @ macro expansion counter
b _commonHandler b _commonHandler
.size \name, . - \name
.endm .endm
.text .text
.arm .arm
.align 4 .balign 4
.global _commonHandler .global _commonHandler
.type _commonHandler, %function .type _commonHandler, %function
_commonHandler: _commonHandler:
mov r1, r0
mov r0, sp
mrs r2, spsr mrs r2, spsr
mov r6, sp
mrs r3, cpsr mrs r3, cpsr
add r6, r0, #(8 * 4)
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11) orr r3, #0xc0 @ mask interrupts
msr cpsr_cx, r3 msr cpsr_cx, r3
tst r2, #0x20
bne noSvcBreak
cmp r1, #2
bne noSvcBreak
sub r0, lr, #4 @ calling cannotAccessAddress cause more problems that it actually solves... (I've to save a lot of regs and that's a pain tbh)
lsr r0, #20 @ we'll just do some address checks (to see if it's in ARM9 internal memory)
cmp r0, #0x80
bne noSvcBreak
ldr r4, [lr, #-4]
ldr r5, =#0xe12fff7f
cmp r4, r5
bne noSvcBreak
bic r5, r3, #0xf
orr r5, #0x3
msr cpsr_c, r5 @ switch to supervisor mode
ldmfd sp, {r8-r11}^
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
ldr r4, [sp, #0x18]
msr cpsr_c, r3 @ restore processor mode
tst r2, #0x20
addne lr, r4, #2 @ adjust address for later
moveq lr, r4
noSvcBreak:
ands r4, r2, #0xf @ get the mode that triggered the exception ands r4, r2, #0xf @ get the mode that triggered the exception
moveq r4, #0xf @ usr => sys moveq r4, #0xf @ usr => sys
bic r5, r3, #0xf bic r5, r3, #0xf
orr r5, r4 orr r5, r4
msr cpsr_c, r5 @ change processor mode msr cpsr_c, r5 @ change processor mode
stmfd r6!, {r8-lr} stmia r6!, {r8-lr}
msr cpsr_c, r3 @ restore processor mode msr cpsr_c, r3 @ restore processor mode
mov sp, r6
stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later str lr, [r6], #4
@ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7 str r2, [r6]
mov r0, sp
msr cpsr_cxsf, #0xdf @ finally, switch to system mode, mask interrupts and clear flags (in case of double faults)
ldr sp, =0x02000000
b mainHandler b mainHandler
GEN_HANDLER FIQHandler
GEN_HANDLER undefinedInstructionHandler
GEN_HANDLER prefetchAbortHandler
GEN_HANDLER dataAbortHandler
.global readMPUConfig .global FIQHandler
.type readMPUConfig, %function .type FIQHandler, %function
readMPUConfig: GEN_USUAL_HANDLER FIQ, 0
stmfd sp!, {r4-r8, lr}
mrc p15,0,r1,c6,c0,0 .global undefinedInstructionHandler
mrc p15,0,r2,c6,c1,0 .type undefinedInstructionHandler, %function
mrc p15,0,r3,c6,c2,0 GEN_USUAL_HANDLER undefinedInstruction, 1
mrc p15,0,r4,c6,c3,0
mrc p15,0,r5,c6,c4,0 .global prefetchAbortHandler
mrc p15,0,r6,c6,c5,0 .type prefetchAbortHandler, %function
mrc p15,0,r7,c6,c6,0 prefetchAbortHandler:
mrc p15,0,r8,c6,c7,0 msr cpsr_cx, #0xd7 @ mask interrupts (abort mode)
stmia r0, {r1-r8} mrs sp, spsr
mrc p15,0,r0,c5,c0,2 @ read data access permission bits and sp, #0x3f
ldmfd sp!, {r4-r8, pc} cmp sp, #0x13
bne _prefetchAbortNormalHandler
ldr sp, =BreakPtr
ldr sp, [sp]
cmp sp, #0
beq _prefetchAbortNormalHandler
add sp, #(1*4 + 4)
cmp lr, sp
bne _prefetchAbortNormalHandler
mov sp, r8
pop {r8-r11}
ldr lr, [sp, #8]!
ldr sp, [sp, #4]
msr spsr_cxsf, sp
tst sp, #0x20
addne lr, #2 @ adjust address for later
GEN_USUAL_HANDLER _prefetchAbortNormal, 2
.global dataAbortHandler
.type dataAbortHandler, %function
dataAbortHandler:
msr cpsr_cx, #0xd7 @ mask interrupts (abort mode)
mrs sp, spsr
and sp, #0x3f
cmp sp, #0x1f
bne _dataAbortNormalHandler
sub lr, #8
adr sp, safecpy
cmp lr, sp
blo _j_dataAbortNormalHandler
adr sp, _safecpy_end
cmp lr, sp
bhs _j_dataAbortNormalHandler
msr spsr_f, #(1 << 30)
mov r12, #0
adds pc, lr, #4
_j_dataAbortNormalHandler:
add lr, #8
GEN_USUAL_HANDLER _dataAbortNormal, 3
.global safecpy
.type safecpy, %function
safecpy:
push {r4, lr}
mov r3, #0
movs r12, #1
_safecpy_loop:
ldrb r4, [r1, r3]
cmp r12, #0
beq _safecpy_loop_end
strb r4, [r0, r3]
add r3, #1
cmp r3, r2
blo _safecpy_loop
_safecpy_loop_end:
mov r0, r3
pop {r4, pc}
_safecpy_end:
.bss
.balign 4
_regs: .skip (4 * 17)

View File

@@ -32,48 +32,10 @@
#define REG_DUMP_SIZE 4 * 17 #define REG_DUMP_SIZE 4 * 17
#define CODE_DUMP_SIZE 48 #define CODE_DUMP_SIZE 48
bool cannotAccessAddress(const void *address) void __attribute__((noreturn)) mainHandler(u32 *registerDump, u32 type)
{
u32 regionSettings[8];
u32 addr = (u32)address;
u32 dataAccessPermissions = readMPUConfig(regionSettings);
for(u32 i = 0; i < 8; i++)
{
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
continue; //No access / region not enabled
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
if(addr >= regionAddrBase && addr < regionAddrBase + regionSize)
return false;
dataAccessPermissions >>= 4;
}
return true;
}
static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment)
{
u8 *out = (u8 *)dst;
const u8 *in = (const u8 *)src;
if(((u32)src & (alignment - 1)) != 0 || cannotAccessAddress(src) || (size != 0 && cannotAccessAddress((u8 *)src + size - 1)))
return 0;
for(u32 i = 0; i < size; i++)
*out++ = *in++;
return size;
}
void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type)
{ {
ExceptionDumpHeader dumpHeader; ExceptionDumpHeader dumpHeader;
u32 registerDump[REG_DUMP_SIZE / 4];
u8 codeDump[CODE_DUMP_SIZE]; u8 codeDump[CODE_DUMP_SIZE];
dumpHeader.magic[0] = 0xDEADC0DE; dumpHeader.magic[0] = 0xDEADC0DE;
@@ -89,34 +51,32 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type)
dumpHeader.codeDumpSize = CODE_DUMP_SIZE; dumpHeader.codeDumpSize = CODE_DUMP_SIZE;
dumpHeader.additionalDataSize = 0; dumpHeader.additionalDataSize = 0;
//Dump registers u32 cpsr = registerDump[16];
//Current order of saved regs: cpsr, pc, r8-r14, r0-r7 u32 pc = registerDump[15] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
u32 cpsr = regs[0];
u32 pc = regs[1] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
registerDump[15] = pc; registerDump[15] = pc;
registerDump[16] = cpsr;
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i];
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
//Dump code //Dump code
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4); dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize);
//Copy register dump and code dump //Copy register dump and code dump
u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader)); u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1); final += safecpy(final, registerDump, dumpHeader.registerDumpSize);
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1); final += safecpy(final, codeDump, dumpHeader.codeDumpSize);
//Dump stack in place //Dump stack in place
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1); dumpHeader.stackDumpSize = safecpy(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF));
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize; dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
//Copy header (actually optimized by the compiler) //Copy header (actually optimized by the compiler)
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader; *(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
if(ARESCREENSINITIALIZED) i2cWriteRegister(I2C_DEV_MCU, 0x22, 1 << 0); //Shutdown LCD
((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed ((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
while(true); while(true);
} }

View File

@@ -26,8 +26,12 @@
.align 4 .align 4
.global _start .global _start
_start: _start:
add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations add pc, r0, #(handlers - .) @ Dummy instruction
.global BreakPtr
BreakPtr: .word 0
.global handlers
handlers: handlers:
.word FIQHandler .word FIQHandler
.word undefinedInstructionHandler .word undefinedInstructionHandler

View File

@@ -39,3 +39,7 @@ typedef volatile u8 vu8;
typedef volatile u16 vu16; typedef volatile u16 vu16;
typedef volatile u32 vu32; typedef volatile u32 vu32;
typedef volatile u64 vu64; typedef volatile u64 vu64;
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)

View File

@@ -90,8 +90,15 @@ def makeRegisterLine(A, rA, B, rB):
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort") handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2") registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)") svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
faultStatusSources = {
0b1:'Alignment', 0b100:'Instruction cache maintenance operation fault',
0b1100:'External Abort on translation - First-level', 0b1110:'External Abort on translation - Second-level',
0b101:'Translation - Section', 0b111:'Translation - Page', 0b11:'Access bit - Section', 0b110:'Access bit - Page',
0b1001:'Domain - Section', 0b1011:'Domain - Page', 0b1101:'Permission - Section', 0b1111:'Permission - Page',
0b1000:'Precise External Abort', 0b10110:'Imprecise External Abort', 0b10:'Debug event'
}
if __name__ == "__main__": def main(args=None):
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps") parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
parser.add_argument("filename") parser.add_argument("filename")
args = parser.parse_args() args = parser.parse_args()
@@ -134,6 +141,11 @@ if __name__ == "__main__":
typeDetailsStr = " (VFP exception)" typeDetailsStr = " (VFP exception)"
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr)) print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
if processor == 11 and exceptionType >= 2:
xfsr = registers[18] if exceptionType == 2 else registers[17]
print("Fault status: " + faultStatusSources[xfsr & 0xf])
if additionalDataSize != 0: if additionalDataSize != 0:
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0])) print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
@@ -143,6 +155,9 @@ if __name__ == "__main__":
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1])) print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1]))) if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
if processor == 11 and exceptionType == 3:
print("{0:<15}{1:<20}Access type: {2}".format("FAR", "{0:08x}".format(registers[19]), "Write" if registers[17] & (1 << 11) != 0 else "Read"))
thumb = registers[16] & 0x20 != 0 thumb = registers[16] & 0x20 != 0
addr = registers[15] - codeDumpSize + (2 if thumb else 4) addr = registers[15] - codeDumpSize + (2 if thumb else 4)
@@ -151,8 +166,9 @@ if __name__ == "__main__":
objdump_res = "" objdump_res = ""
try: try:
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump") path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
if os.name == "nt":
path = ''.join((path[1], ':', path[2:])).replace('/', '\\') if os.name == "nt" and path[0] == '/':
path = ''.join((path[1], ':', path[2:]))
objdump_res = subprocess.check_output(( objdump_res = subprocess.check_output((
path, "-marm", "-b", "binary", path, "-marm", "-b", "binary",
@@ -167,3 +183,6 @@ if __name__ == "__main__":
print("\nStack dump:\n") print("\nStack dump:\n")
print(hexdump(registers[13], stackDump)) print(hexdump(registers[13], stackDump))
if __name__ == "__main__":
main()

View File

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

View File

@@ -12,12 +12,14 @@
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1) #define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
enum multiOptions enum multiOptions
{ {
DEFAULTEMU = 0, DEFAULTEMU = 0,
BRIGHTNESS, BRIGHTNESS,
SPLASH, SPLASH,
SPLASH_DURATION,
PIN, PIN,
NEWCPU NEWCPU
}; };
@@ -30,7 +32,6 @@ enum singleOptions
PATCHGAMES, PATCHGAMES,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHACCESS,
PATCHUNITINFO, PATCHUNITINFO,
DISABLEARM11EXCHANDLERS DISABLEARM11EXCHANDLERS
}; };

View File

@@ -0,0 +1,39 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#pragma once
#include "types.h"
#include "globals.h"
#include "kernel.h"
#include "utils.h"
extern KRecursiveLock dbgParamsLock;
extern u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId;
KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this, u32 interruptID);
KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this, u32 interruptID);
KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this, u32 interruptID);

View File

@@ -56,6 +56,7 @@ extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
extern void (*SleepThread)(s64 ns); extern void (*SleepThread)(s64 ns);
extern Result (*CloseHandle)(Handle handle); extern Result (*CloseHandle)(Handle handle);
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
extern Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type); extern Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
extern Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type); extern Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);

View File

@@ -1137,21 +1137,29 @@ typedef struct FcramLayout
extern bool isN3DS; extern bool isN3DS;
extern void *officialSVCs[0x7E]; extern void *officialSVCs[0x7E];
#define KPROCESS_OFFSETOF(field) (isN3DS ? offsetof(KProcessN3DS, field) :\ #define KPROCESSRELATED_OFFSETOFF(classname, field) (isN3DS ? offsetof(classname##N3DS, field) :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(KProcessO3DS8x, field) :\ ((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(classname##O3DS8x, field) :\
offsetof(KProcessO3DSPre8x, field))) offsetof(classname##O3DSPre8x, field)))
#define KPROCESS_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\ #define KPROCESSRELATED_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\ ((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\
&(obj)->O3DSPre8x.field )) &(obj)->O3DSPre8x.field))
#define KPROCESS_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\ #define KPROCESSRELATED_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\ ((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\
(type *)(&(obj)->O3DSPre8x.field) )) (type *)(&(obj)->O3DSPre8x.field)))
#define KPROCESS_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcess, field)
#define KPROCESS_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
#define KPROCESS_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field)) #define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field))
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR_TYPE(type, obj, field))
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR(type, obj, field)) #define KPROCESSHWINFO_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcessHwInfo, field)
#define KPROCESSHWINFO_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
#define KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
#define KPROCESSHWINFO_GET_RVALUE(obj, field) *(KPROCESSHWINFO_GET_PTR(obj, field))
#define KPROCESSHWINFO_GET_RVALUE_TYPE(type, obj, field) *(KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field))
static inline u32 idOfProcess(KProcess *process) static inline u32 idOfProcess(KProcess *process)
{ {
@@ -1178,6 +1186,20 @@ static inline KDebug *debugOfProcess(KProcess *process)
return KPROCESS_GET_RVALUE(process, debug); return KPROCESS_GET_RVALUE(process, debug);
} }
static inline const char *classNameOfAutoObject(KAutoObject *object)
{
const char *name;
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
{
KClassToken tok;
object->vtable->GetClassToken(&tok, object);
name = tok.name;
}
else
name = object->vtable->GetClassName(object);
return name;
}
extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token); extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj) static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj)

View File

@@ -0,0 +1,34 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#pragma once
#include "utils.h"
#include "kernel.h"
#include "svc.h"
Result GetHandleInfoHookWrapper(u32 dummy, Handle handle, u32 type);
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type);

View File

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

View File

@@ -0,0 +1,147 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "debug.h"
#include "memory.h"
#include "synchronization.h"
KRecursiveLock dbgParamsLock = { NULL };
u32 dbgParamWatchpointId, dbgParamDVA, dbgParamWCR, dbgParamContextId;
KSchedulableInterruptEvent *enableMonitorModeDebugging(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
{
coreBarrier();
u32 DSCR;
__asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 0" : [val] "=r" (DSCR));
DSCR |= 0x8000;
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 0" :: [val] "r" (DSCR));
__dsb();
coreBarrier();
return NULL;
}
static void disableWatchpoint0(void)
{
u32 control;
// WCR0
__asm__ __volatile__("mrc p14, 0, %[val], c0, c0, 7" : [val] "=r" (control));
control &= ~1;
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (control));
// BCR4
__asm__ __volatile__("mrc p14, 0, %[val], c0, c4, 5" : [val] "=r" (control));
control &= ~1;
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (control));
}
static void disableWatchpoint1(void)
{
u32 control;
// WCR1
__asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 7" : [val] "=r" (control));
control &= ~1;
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (control));
// BCR5
__asm__ __volatile__("mrc p14, 0, %[val], c0, c5, 5" : [val] "=r" (control));
control &= ~1;
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (control));
}
KSchedulableInterruptEvent *disableWatchpoint(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
{
coreBarrier();
if(dbgParamWatchpointId == 0)
disableWatchpoint0();
else
disableWatchpoint1();
__dsb();
coreBarrier();
return NULL;
}
static void setWatchpoint0WithContextId(u32 DVA, u32 WCR, u32 contextId)
{
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
u32 BCR =
(1 << 21) | /* compare with context ID */
(1 << 20) | /* linked (with a WRP in our case) */
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
(1 << 0) ; /* enabled */
disableWatchpoint0();
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 6" :: [val] "r" (DVA));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 4" :: [val] "r" (contextId));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (WCR));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (BCR));
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
}
static void setWatchpoint1WithContextId(u32 DVA, u32 WCR, u32 contextId)
{
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
u32 BCR =
(1 << 21) | /* compare with context ID */
(1 << 20) | /* linked (with a WRP in our case) */
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
(1 << 0) ; /* enabled */
disableWatchpoint1();
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 6" :: [val] "r" (DVA));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 4" :: [val] "r" (contextId));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (WCR));
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (BCR));
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
}
KSchedulableInterruptEvent *setWatchpointWithContextId(KBaseInterruptEvent *this UNUSED, u32 interruptID UNUSED)
{
coreBarrier();
if(dbgParamWatchpointId == 0)
setWatchpoint0WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId);
else
setWatchpoint1WithContextId(dbgParamDVA, dbgParamWCR, dbgParamContextId);
__dsb();
coreBarrier();
return NULL;
}

View File

@@ -159,7 +159,7 @@ _commonHandler:
_no_L2C: _no_L2C:
cps #0x1F msr cpsr_cxsf, #0xdf @ finally, switch to system mode, mask interrupts and clear flags (in case of double faults)
ldr sp, =exceptionStackTop ldr sp, =exceptionStackTop
ldr sp, [sp] ldr sp, [sp]
sub sp, #0x100 sub sp, #0x100
@@ -221,7 +221,8 @@ prefetchAbortHandler:
pop {r8-r11} pop {r8-r11}
ldr lr, [sp, #8]! ldr lr, [sp, #8]!
ldr sp, [sp, #4] ldr sp, [sp, #4]
msr spsr, sp msr spsr_cxsf, sp
tst sp, #0x20
addne lr, #2 @ adjust address for later addne lr, #2 @ adjust address for later
GEN_USUAL_HANDLER _prefetchAbortNormal, 2, 12 GEN_USUAL_HANDLER _prefetchAbortNormal, 2, 12

View File

@@ -37,7 +37,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
{ {
if(CONFIG(DISABLEARM11EXCHANDLERS)) return false; if(CONFIG(DISABLEARM11EXCHANDLERS)) return false;
if((spsr & 0x1f) != 0x10) return true; if((spsr & 0x1F) != 0x10) return true;
KThread *thread = currentCoreContext->objectContext.currentThread; KThread *thread = currentCoreContext->objectContext.currentThread;
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
@@ -65,7 +65,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
extern u32 safecpy_sz; extern u32 safecpy_sz;
bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr) bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr)
{ {
return ((spsr & 0x1F) != 0x10) && ( return (!(spsr & 0x20) && (spsr & 0x1F) != 0x10) && (
((u32)kernelUsrCopyFuncsStart <= addr && addr < (u32)kernelUsrCopyFuncsEnd) || ((u32)kernelUsrCopyFuncsStart <= addr && addr < (u32)kernelUsrCopyFuncsEnd) ||
((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz) ((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz)
); );
@@ -96,7 +96,7 @@ void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
registerDump[15] = pc; registerDump[15] = pc;
//Dump code //Dump code
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem
dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize); dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize);
//Copy register dump and code dump //Copy register dump and code dump

View File

@@ -52,6 +52,7 @@ void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
void (*SleepThread)(s64 ns); void (*SleepThread)(s64 ns);
Result (*CloseHandle)(Handle handle); Result (*CloseHandle)(Handle handle);
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type); Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type); Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);

View File

@@ -208,6 +208,7 @@ static void findUsefulSymbols(void)
decodeARMBranch((u32 *)officialSVCs[0x01] + 5); decodeARMBranch((u32 *)officialSVCs[0x01] + 5);
SleepThread = (void (*)(s64))officialSVCs[0x0A]; SleepThread = (void (*)(s64))officialSVCs[0x0A];
CloseHandle = (Result (*)(Handle))officialSVCs[0x23]; CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x29] + 3);
GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3); GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3);
GetProcessInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2B] + 3); GetProcessInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2B] + 3);
GetThreadInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2C] + 3); GetThreadInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2C] + 3);

View File

@@ -28,9 +28,10 @@
#include "synchronization.h" #include "synchronization.h"
#include "svc.h" #include "svc.h"
#include "svc/ControlMemory.h" #include "svc/ControlMemory.h"
#include "svc/GetHandleInfo.h"
#include "svc/GetSystemInfo.h"
#include "svc/GetProcessInfo.h" #include "svc/GetProcessInfo.h"
#include "svc/GetThreadInfo.h" #include "svc/GetThreadInfo.h"
#include "svc/GetSystemInfo.h"
#include "svc/GetCFWInfo.h" #include "svc/GetCFWInfo.h"
#include "svc/ConnectToPort.h" #include "svc/ConnectToPort.h"
#include "svc/SendSyncRequest.h" #include "svc/SendSyncRequest.h"
@@ -103,6 +104,8 @@ void *svcHook(u8 *pageEnd)
doingVeryShittyPmResLimitWorkaround = true; doingVeryShittyPmResLimitWorkaround = true;
} }
return officialSVCs[0x17]; return officialSVCs[0x17];
case 0x29:
return GetHandleInfoHookWrapper;
case 0x2A: case 0x2A:
return GetSystemInfoHookWrapper; return GetSystemInfoHookWrapper;
case 0x2B: case 0x2B:

View File

@@ -42,20 +42,12 @@ Result ControlService(ServiceOp op, u32 varg1, u32 varg2)
KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTable, (Handle)varg2); KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTable, (Handle)varg2);
if(obj == NULL) if(obj == NULL)
return 0xD8E007F7; // invalid handle return 0xD8E007F7; // invalid handle
else if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
{
KClassToken tok;
obj->vtable->GetClassToken(&tok, obj);
if(tok.flags == 0x95)
session = ((KServerSession *)obj)->parentSession;
else if(tok.flags == 0xA5)
session = ((KClientSession *)obj)->parentSession;
}
else else
{ // not the exact same tests but it should work {
if(strcmp(obj->vtable->GetClassName(obj), "KServerSession") == 0) // not the exact same tests but it should work
if(strcmp(classNameOfAutoObject(obj), "KServerSession") == 0)
session = ((KServerSession *)obj)->parentSession; session = ((KServerSession *)obj)->parentSession;
else if(strcmp(obj->vtable->GetClassName(obj), "KClientSession") == 0) else if(strcmp(classNameOfAutoObject(obj), "KClientSession") == 0)
session = ((KClientSession *)obj)->parentSession; session = ((KClientSession *)obj)->parentSession;
} }

View File

@@ -0,0 +1,62 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "svc/GetThreadInfo.h"
#include "memory.h"
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
{
if(type == 0x10000) // KDebug and KProcess: get context ID
{
KProcessHwInfo *hwInfo;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KAutoObject *obj;
if(handle == CUR_PROCESS_HANDLE)
{
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
KAutoObject__AddReference(obj);
}
else
obj = KProcessHandleTable__ToKAutoObject(handleTable, handle);
if(obj == NULL)
return 0xD8E007F7;
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
hwInfo = hwInfoOfProcess((KProcess *)obj);
else
hwInfo = NULL;
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
obj->vtable->DecrementReferenceCount(obj);
return 0;
}
else
return GetHandleInfo(out, handle, type);
}

View File

@@ -73,12 +73,12 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
*out = (s64)(u64)(u32)codeSetOfProcess(process)->dataSection.section.loadAddress; *out = (s64)(u64)(u32)codeSetOfProcess(process)->dataSection.section.loadAddress;
break; break;
case 0x10008: case 0x10008:
*out = (isN3DS ? hwInfoOfProcess(process)->N3DS.translationTableBase : {
(kernelVersion >= SYSTEM_VERSION(2, 44, 6) KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
? hwInfoOfProcess(process)->O3DS8x.translationTableBase u32 ttb = KPROCESSHWINFO_GET_RVALUE(hwInfo, translationTableBase);
: hwInfoOfProcess(process)->O3DSPre8x.translationTableBase) *out = ttb & ~((1 << (14 - TTBCR)) - 1);
) & ~((1 << (14 - TTBCR)) - 1);
break; break;
}
default: default:
res = 0xD8E007ED; // invalid enum value res = 0xD8E007ED; // invalid enum value
break; break;

View File

@@ -27,6 +27,7 @@
#include "svc/KernelSetState.h" #include "svc/KernelSetState.h"
#include "synchronization.h" #include "synchronization.h"
#include "ipc.h" #include "ipc.h"
#include "debug.h"
#include "memory.h" #include "memory.h"
#define MAX_DEBUG 3 #define MAX_DEBUG 3
@@ -142,7 +143,41 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
res = SetSyscallDebugEventMask(varg1, (bool)varg2, (const u32 *)varg3); res = SetSyscallDebugEventMask(varg1, (bool)varg2, (const u32 *)varg3);
break; break;
} }
case 0x10003:
{
executeFunctionOnCores(enableMonitorModeDebugging, 0xF, 0);
break;
}
case 0x10004:
{
KRecursiveLock__Lock(&dbgParamsLock);
dbgParamWatchpointId = varg1;
executeFunctionOnCores(disableWatchpoint, 0xF, 0);
KRecursiveLock__Unlock(&dbgParamsLock);
break;
}
case 0x10005:
{
KRecursiveLock__Lock(&dbgParamsLock);
dbgParamWatchpointId = 0;
dbgParamDVA = varg1;
dbgParamWCR = varg2;
dbgParamContextId = varg3;
executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0);
KRecursiveLock__Unlock(&dbgParamsLock);
break;
}
case 0x10006:
{
KRecursiveLock__Lock(&dbgParamsLock);
dbgParamWatchpointId = 1;
dbgParamDVA = varg1;
dbgParamWCR = varg2;
dbgParamContextId = varg3;
executeFunctionOnCores(setWatchpointWithContextId, 0xF, 0);
KRecursiveLock__Unlock(&dbgParamsLock);
break;
}
default: default:
{ {
res = KernelSetState(type, varg1, varg2, varg3); res = KernelSetState(type, varg1, varg2, varg3);

View File

@@ -37,15 +37,8 @@ Result SendSyncRequestHook(Handle handle)
bool skip = false; bool skip = false;
Result res = 0; Result res = 0;
bool isValidClientSession = false; // not the exact same test but it should work
if(clientSession != NULL && kernelVersion >= SYSTEM_VERSION(2, 46, 0)) bool isValidClientSession = clientSession != NULL && strcmp(classNameOfAutoObject(&clientSession->syncObject.autoObject), "KClientSession") == 0;
{
KClassToken tok;
clientSession->syncObject.autoObject.vtable->GetClassToken(&tok, &clientSession->syncObject.autoObject);
isValidClientSession = tok.flags == 0xA5;
}
else if(clientSession != NULL) // not the exact same test but it should work
isValidClientSession = strcmp(clientSession->syncObject.autoObject.vtable->GetClassName(&clientSession->syncObject.autoObject), "KClientSession") == 0;
if(isValidClientSession) if(isValidClientSession)
{ {
@@ -54,7 +47,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x10042: case 0x10042:
{ {
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "srv:pm") == 0) if(info != NULL && kernelVersion >= SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
{ {
res = doPublishToProcessHook(handle, cmdbuf); res = doPublishToProcessHook(handle, cmdbuf);
skip = true; skip = true;
@@ -112,7 +105,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x50100: case 0x50100:
{ {
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "srv:") == 0) if(info != NULL && (strcmp(info->name, "srv:") == 0 || (kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)))
{ {
char name[9] = { 0 }; char name[9] = { 0 };
memcpy(name, cmdbuf + 1, 8); memcpy(name, cmdbuf + 1, 8);
@@ -126,6 +119,7 @@ Result SendSyncRequestHook(Handle handle)
outClientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, (Handle)cmdbuf[3]); outClientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, (Handle)cmdbuf[3]);
if(outClientSession != NULL) if(outClientSession != NULL)
{ {
if(strcmp(classNameOfAutoObject(&outClientSession->syncObject.autoObject), "KClientSession") == 0)
SessionInfo_Add(outClientSession->parentSession, name); SessionInfo_Add(outClientSession->parentSession, name);
outClientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&outClientSession->syncObject.autoObject); outClientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&outClientSession->syncObject.autoObject);
} }
@@ -163,7 +157,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x4010042: case 0x4010042:
{ {
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "srv:pm") == 0) if(info != NULL && kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
{ {
res = doPublishToProcessHook(handle, cmdbuf); res = doPublishToProcessHook(handle, cmdbuf);
skip = true; skip = true;

View File

@@ -26,10 +26,12 @@
#include "svc/SetWifiEnabled.h" #include "svc/SetWifiEnabled.h"
void SetWifiEnabled(bool enable) Result SetWifiEnabled(bool enable)
{ {
if(enable) if(enable)
CFG11_WIFICNT |= 1; CFG11_WIFICNT |= 1;
else else
CFG11_WIFICNT &= ~1; CFG11_WIFICNT &= ~1;
return 0;
} }

View File

@@ -50,14 +50,7 @@ Result TranslateHandle(u32 *outKAddr, char *outClassName, Handle handle)
if(obj == NULL) if(obj == NULL)
return 0xD8E007F7; // invalid handle return 0xD8E007F7; // invalid handle
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0)) name = classNameOfAutoObject(obj);
{
KClassToken tok;
obj->vtable->GetClassToken(&tok, obj);
name = tok.name;
}
else
name = obj->vtable->GetClassName(obj);
if(name == NULL) // shouldn't happen if(name == NULL) // shouldn't happen
name = "KAutoObject"; name = "KAutoObject";

View File

@@ -37,6 +37,7 @@
pop {r1, r2, r12, pc} pop {r1, r2, r12, pc}
.endm .endm
GEN_GETINFO_WRAPPER Handle
GEN_GETINFO_WRAPPER System GEN_GETINFO_WRAPPER System
GEN_GETINFO_WRAPPER Process GEN_GETINFO_WRAPPER Process
GEN_GETINFO_WRAPPER Thread GEN_GETINFO_WRAPPER Thread

View File

@@ -116,9 +116,7 @@ fname: .ascii "FILE"
.align 4 .align 4
kernelcode_start: kernelcode_start:
mrs r0, cpsr ; disable interrupts msr cpsr_cxsf, #0xD3 ; disable interrupts and clear flags
orr r0, #0xC0
msr cpsr, r0
ldr sp, =copy_launch_stub_stack_top ldr sp, =copy_launch_stub_stack_top

View File

@@ -45,7 +45,8 @@
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN) #define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP) #define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y) #define SINGLE_PAYLOAD_BUTTONS (BUTTON_B | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT) #define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START) #define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT) #define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT)
#define NTRBOOT_BUTTONS (BUTTON_START | BUTTON_SELECT | BUTTON_X)

View File

@@ -27,6 +27,7 @@
#include "config.h" #include "config.h"
#include "memory.h" #include "memory.h"
#include "fs.h" #include "fs.h"
#include "strings.h"
#include "utils.h" #include "utils.h"
#include "screen.h" #include "screen.h"
#include "draw.h" #include "draw.h"
@@ -78,25 +79,25 @@ void writeConfig(bool isConfigOptions)
void configMenu(bool oldPinStatus, u32 oldPinMode) void configMenu(bool oldPinStatus, u32 oldPinMode)
{ {
const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )", static const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
"Screen brightness: 4( ) 3( ) 2( ) 1( )", "Screen brightness: 4( ) 3( ) 2( ) 1( )",
"Splash: Off( ) Before( ) After( ) payloads", "Splash: Off( ) Before( ) After( ) payloads",
"Splash duration: 1( ) 3( ) 5( ) 7( ) seconds",
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits", "PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )", "New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
}; };
const char *singleOptionsText[] = { "( ) Autoboot EmuNAND", static const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
"( ) Use EmuNAND FIRM if booting with R", "( ) Use EmuNAND FIRM if booting with R",
"( ) Enable loading external FIRMs and modules", "( ) Enable loading external FIRMs and modules",
"( ) Enable game patching", "( ) Enable game patching",
"( ) Show NAND or user string in System Settings", "( ) Show NAND or user string in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Patch ARM9 access",
"( ) Set developer UNITINFO", "( ) Set developer UNITINFO",
"( ) Disable ARM11 exception handlers", "( ) Disable ARM11 exception handlers",
}; };
const char *optionsDescription[] = { "Select the default EmuNAND.\n\n" static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
"It will be booted when no\n" "It will be booted when no\n"
"directional pad buttons are pressed.", "directional pad buttons are pressed.",
@@ -110,6 +111,11 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"\t* 'After payloads' displays it\n" "\t* 'After payloads' displays it\n"
"afterwards.", "afterwards.",
"Select how long the splash screen\n"
"displays.\n\n"
"This has no effect if the splash\n"
"screen is not enabled.",
"Activate a PIN lock.\n\n" "Activate a PIN lock.\n\n"
"The PIN will be asked each time\n" "The PIN will be asked each time\n"
"Luma3DS boots.\n\n" "Luma3DS boots.\n\n"
@@ -152,7 +158,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"Enable overriding the region and\n" "Enable overriding the region and\n"
"language configuration and the usage\n" "language configuration and the usage\n"
"of patched code binaries,\n" "of patched code binaries, exHeaders,\n"
"IPS code patches and LayeredFS\n" "IPS code patches and LayeredFS\n"
"for specific games.\n\n" "for specific games.\n\n"
"Also makes certain DLCs\n" "Also makes certain DLCs\n"
@@ -174,10 +180,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"Enable showing the GBA boot screen\n" "Enable showing the GBA boot screen\n"
"when booting GBA games.", "when booting GBA games.",
"Disable ARM9 exheader access checks.\n\n"
"Only select this if you know what you\n"
"are doing!",
"Make the console be always detected\n" "Make the console be always detected\n"
"as a development unit, and conversely.\n" "as a development unit, and conversely.\n"
"(which breaks online features, amiibo\n" "(which breaks online features, amiibo\n"
@@ -200,11 +202,12 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
u32 enabled; u32 enabled;
bool visible; bool visible;
} multiOptions[] = { } multiOptions[] = {
{ .posXs = {19, 24, 29, 34}, .visible = isSdMode }, { .visible = isSdMode },
{ .posXs = {21, 26, 31, 36}, .visible = true }, { .visible = true },
{ .posXs = {12, 22, 31, 0}, .visible = true }, { .visible = true },
{ .posXs = {14, 19, 24, 29}, .visible = true }, { .visible = true },
{ .posXs = {17, 26, 32, 44}, .visible = ISN3DS }, { .visible = true },
{ .visible = ISN3DS },
}; };
struct singleOption { struct singleOption {
@@ -219,7 +222,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
{ .visible = true }, { .visible = true },
{ .visible = true }, { .visible = true },
{ .visible = true }, { .visible = true },
{ .visible = true },
{ .visible = true } { .visible = true }
}; };
@@ -233,14 +235,28 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
//Parse the existing options //Parse the existing options
for(u32 i = 0; i < multiOptionsAmount; i++) for(u32 i = 0; i < multiOptionsAmount; i++)
{
//Detect the positions where the "x" should go
u32 optionNum = 0;
for(u32 j = 0; optionNum < 4 && j < strlen(multiOptionsText[i]); j++)
if(multiOptionsText[i][j] == '(') multiOptions[i].posXs[optionNum++] = j + 1;
while(optionNum < 4) multiOptions[i].posXs[optionNum++] = 0;
multiOptions[i].enabled = MULTICONFIG(i); multiOptions[i].enabled = MULTICONFIG(i);
}
for(u32 i = 0; i < singleOptionsAmount; i++) for(u32 i = 0; i < singleOptionsAmount; i++)
singleOptions[i].enabled = CONFIG(i); singleOptions[i].enabled = CONFIG(i);
initScreens(); initScreens();
static const char *bootTypes[] = { "B9S",
"B9S (ntrboot)",
"FIRM0",
"FIRM1" };
drawString(true, 10, 10, COLOR_TITLE, CONFIG_TITLE); drawString(true, 10, 10, COLOR_TITLE, CONFIG_TITLE);
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to save"); drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to save");
drawFormattedString(false, 10, SCREEN_HEIGHT - 2 * SPACING_Y, COLOR_YELLOW, "Booted from %s via %s", isSdMode ? "SD" : "CTRNAND", bootTypes[(u32)bootType]);
//Character to display a selected option //Character to display a selected option
char selected = 'x'; char selected = 'x';
@@ -284,9 +300,9 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
u32 pressed; u32 pressed;
do do
{ {
pressed = waitInput(true); pressed = waitInput(true) & MENU_BUTTONS;
} }
while(!(pressed & MENU_BUTTONS)); while(!pressed);
if(pressed == BUTTON_START) break; if(pressed == BUTTON_START) break;
@@ -389,12 +405,16 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
for(u32 i = 0; i < singleOptionsAmount; i++) for(u32 i = 0; i < singleOptionsAmount; i++)
configData.config |= (singleOptions[i].enabled ? 1 : 0) << i; configData.config |= (singleOptions[i].enabled ? 1 : 0) << i;
writeConfig(true);
u32 newPinMode = MULTICONFIG(PIN); u32 newPinMode = MULTICONFIG(PIN);
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode); if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
else if(oldPinStatus) fileDelete(PIN_FILE); else if(oldPinStatus)
{
writeConfig(true); if(!fileDelete(PIN_FILE))
error("Unable to delete PIN file");
}
while(HID_PAD & PIN_BUTTONS); while(HID_PAD & PIN_BUTTONS);
wait(2000ULL); wait(2000ULL);

View File

@@ -34,17 +34,19 @@
#define CONFIG_FILE "config.bin" #define CONFIG_FILE "config.bin"
#define CONFIG_VERSIONMAJOR 2 #define CONFIG_VERSIONMAJOR 2
#define CONFIG_VERSIONMINOR 0 #define CONFIG_VERSIONMINOR 3
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1) #define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
enum multiOptions enum multiOptions
{ {
DEFAULTEMU = 0, DEFAULTEMU = 0,
BRIGHTNESS, BRIGHTNESS,
SPLASH, SPLASH,
SPLASH_DURATION,
PIN, PIN,
NEWCPU NEWCPU
}; };
@@ -57,7 +59,6 @@ enum singleOptions
PATCHGAMES, PATCHGAMES,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHACCESS,
PATCHUNITINFO, PATCHUNITINFO,
DISABLEARM11EXCHANDLERS DISABLEARM11EXCHANDLERS
}; };

View File

@@ -327,7 +327,7 @@ __attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE];
static u8 nandSlot; static u8 nandSlot;
static u32 fatStart = 0; static u32 fatStart = 0;
FirmwareSource firmSource; FirmwareSource firmSource = FIRMWARE_SYSNAND;
__attribute__((aligned(4))) static const u8 key1s[2][AES_BLOCK_SIZE] = { __attribute__((aligned(4))) static const u8 key1s[2][AES_BLOCK_SIZE] = {
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},

View File

@@ -36,6 +36,7 @@
#include "fs.h" #include "fs.h"
#include "fmt.h" #include "fmt.h"
#include "font.h" #include "font.h"
#include "config.h"
bool loadSplash(void) bool loadSplash(void)
{ {
@@ -49,7 +50,6 @@ bool loadSplash(void)
if(!isTopSplashValid && !isBottomSplashValid) return false; if(!isTopSplashValid && !isBottomSplashValid) return false;
initScreens(); initScreens();
clearScreens(true);
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE; if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE; if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
@@ -57,7 +57,9 @@ bool loadSplash(void)
if(!isTopSplashValid && !isBottomSplashValid) return false; if(!isTopSplashValid && !isBottomSplashValid) return false;
swapFramebuffers(true); swapFramebuffers(true);
wait(3000ULL);
u32 durationIndex = MULTICONFIG(SPLASH_DURATION);
wait(1000ULL + (durationIndex * 2000ULL));
return true; return true;
} }

View File

@@ -28,8 +28,10 @@
* Code for locating the SDMMC struct by Normmatt * Code for locating the SDMMC struct by Normmatt
*/ */
#include "emunand.h" #include "emunand.h"
#include "memory.h" #include "memory.h"
#include "utils.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
#include "../build/bundled.h" #include "../build/bundled.h"

View File

@@ -32,11 +32,12 @@
#include "draw.h" #include "draw.h"
#include "utils.h" #include "utils.h"
#include "fmt.h" #include "fmt.h"
#include "buttons.h"
#include "../build/bundled.h" #include "../build/bundled.h"
void installArm9Handlers(void) void installArm9Handlers(void)
{ {
memcpy((void *)0x01FF8000, arm9_exceptions_bin + 32, arm9_exceptions_bin_size - 32); memcpy((void *)0x01FF8000, arm9_exceptions_bin, arm9_exceptions_bin_size);
/* IRQHandler is at 0x08000000, but we won't handle it for some reasons /* IRQHandler is at 0x08000000, but we won't handle it for some reasons
svcHandler is at 0x08000010, but we won't handle svc either */ svcHandler is at 0x08000010, but we won't handle svc either */
@@ -46,8 +47,10 @@ void installArm9Handlers(void)
for(u32 i = 0; i < 4; i++) for(u32 i = 0; i < 4; i++)
{ {
*(vu32 *)(0x08000000 + offsets[i]) = 0xE51FF004; *(vu32 *)(0x08000000 + offsets[i]) = 0xE51FF004;
*(vu32 *)(0x08000000 + offsets[i] + 4) = *((u32 *)arm9_exceptions_bin + 1 + i); *(vu32 *)(0x08000000 + offsets[i] + 4) = *(vu32 *)(0x01FF8008 + 4 * i);
} }
*(vu32 *)0x01FF8004 = 0; //BreakPtr
} }
void detectAndProcessExceptionDumps(void) void detectAndProcessExceptionDumps(void)
@@ -69,6 +72,18 @@ void detectAndProcessExceptionDumps(void)
*registerNames[] = { *registerNames[] = {
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
"SP", "LR", "PC", "CPSR", "FPEXC" "SP", "LR", "PC", "CPSR", "FPEXC"
},
*faultStatusNames[] = {
"Alignment", "Instr.cache maintenance op.",
"Ext.Abort on translation - Lv1", "Ext.Abort on translation - Lv2",
"Translation - Section", "Translation - Page", "Access bit - Section", "Access bit - Page",
"Domain - Section", "Domain - Page", "Permission - Section", "Permission - Page",
"Precise External Abort", "Imprecise External Abort", "Debug event"
};
static const u32 faultStatusValues[] = {
0b1, 0b100, 0b1100, 0b1110, 0b101, 0b111, 0b11, 0b110, 0b1001, 0b1011, 0b1101,
0b1111, 0b1000, 0b10110, 0b10
}; };
initScreens(); initScreens();
@@ -98,11 +113,25 @@ void detectAndProcessExceptionDumps(void)
else else
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]); posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
} }
else
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
} }
else else
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]); posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0) if(dumpHeader->processor == 11 && dumpHeader->type >= 2)
{
u32 xfsr = (dumpHeader->type == 2 ? regs[18] : regs[17]) & 0xF;
for(u32 i = 0; i < 15; i++)
if(xfsr == faultStatusValues[i])
{
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Fault status: %s", faultStatusNames[i]);
break;
}
}
if(dumpHeader->additionalDataSize != 0)
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE,
"Current process: %.8s (%016llX)", (const char *)additionalData, *(vu64 *)(additionalData + 8)); "Current process: %.8s (%016llX)", (const char *)additionalData, *(vu64 *)(additionalData + 8));
posY += SPACING_Y; posY += SPACING_Y;
@@ -117,6 +146,9 @@ void detectAndProcessExceptionDumps(void)
posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[20]); posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[20]);
} }
if(dumpHeader->processor == 11 && dumpHeader->type == 3)
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%-7s%08X Access type: %s", "FAR", regs[19], regs[17] & (1u << 11) ? "Write" : "Read");
posY += SPACING_Y; posY += SPACING_Y;
u32 mode = regs[16] & 0xF; u32 mode = regs[16] & 0xF;
@@ -133,6 +165,16 @@ void detectAndProcessExceptionDumps(void)
drawFormattedString(false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE, "%02X", *stackDump); drawFormattedString(false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE, "%02X", *stackDump);
} }
static const char *choiceMessage[] = {"Press A to save the crash dump", "Press any other button to shutdown"};
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, choiceMessage[0]);
drawString(true, 10, posY + SPACING_Y + SPACING_Y , COLOR_WHITE, choiceMessage[1]);
if(waitInput(false) != BUTTON_A) goto exit;
drawString(true, 10, posY + SPACING_Y, COLOR_BLACK, choiceMessage[0]);
drawString(true, 10, posY + SPACING_Y + SPACING_Y , COLOR_BLACK, choiceMessage[1]);
char folderPath[12], char folderPath[12],
path[36], path[36],
fileName[24]; fileName[24];
@@ -143,15 +185,16 @@ void detectAndProcessExceptionDumps(void)
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize)) if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
{ {
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find a dump in the following file:"); posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find the dump in the following file:");
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, path) + SPACING_Y; posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%s:/luma/%s", isSdMode ? "SD" : "CTRNAND", path) + SPACING_Y;
} }
else posY = drawString(true, 10, posY + SPACING_Y, COLOR_RED, "Error writing the dump file"); else posY = drawString(true, 10, posY + SPACING_Y, COLOR_RED, "Error writing the dump file");
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Press any button to shutdown"); drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
waitInput(false); waitInput(false);
exit:
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
mcuPowerOff(); mcuPowerOff();
} }

View File

@@ -286,3 +286,17 @@ R0.12c (March 04, 2017)
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
R0.13 (May 21, 2017)
Changed heading character of configuration keywords "_" to "FF_".
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
Improved cluster allocation time on stretch a deep buried cluster chain.
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)

View File

@@ -1,4 +1,4 @@
FatFs Module Source Files R0.12c FatFs Module Source Files R0.13
FILES FILES
@@ -11,11 +11,12 @@ FILES
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 modules. ffunicode.c Optional Unicode utility functions.
ffsystem.c An example of optional O/S related functions.
Low level disk I/O module is not included in this archive because the FatFs Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and it does not depend on any specific module is only a generic file system layer and it does not depend on any specific
storage device. You have to provide a low level disk I/O module written to storage device. You need to provide a low level disk I/O module written to
control the storage device that attached to the target system. control the storage device that attached to the target system.

View File

@@ -76,7 +76,7 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
return ((pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, buff)) || return ((pdrv == SDCARD && (*(vu16 *)(SDMMC_BASE + REG_SDSTATUS0) & TMIO_STAT0_WRPROTECT) != 0 && !sdmmc_sdcard_writesectors(sector, count, buff)) ||
(pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR; (pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR;
} }
#endif #endif
@@ -91,12 +91,11 @@ DRESULT disk_write (
DRESULT disk_ioctl ( DRESULT disk_ioctl (
__attribute__((unused)) __attribute__((unused))
BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE pdrv, /* Physical drive nmuber (0..) */
__attribute__((unused))
BYTE cmd, /* Control code */ BYTE cmd, /* Control code */
__attribute__((unused)) __attribute__((unused))
void *buff /* Buffer to send/receive control data */ void *buff /* Buffer to send/receive control data */
) )
{ {
return RES_PARERR; return cmd == CTRL_SYNC ? RES_OK : RES_PARERR;
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT file system module R0.12c / / FatFs - Generic FAT Filesystem module R0.13 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2017, ChaN, all right reserved. / Copyright (C) 2017, ChaN, all right reserved.
@@ -15,11 +15,12 @@
/ and any warranties related to this software are DISCLAIMED. / and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software. / by use of this software.
/
/----------------------------------------------------------------------------*/ /----------------------------------------------------------------------------*/
#ifndef _FATFS #ifndef FF_DEFINED
#define _FATFS 68300 /* Revision ID */ #define FF_DEFINED 87030 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -28,7 +29,7 @@ extern "C" {
#include "integer.h" /* Basic integer types */ #include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #if FF_DEFINED != FFCONF_DEF
#error Wrong configuration file (ffconf.h). #error Wrong configuration file (ffconf.h).
#endif #endif
@@ -36,7 +37,7 @@ extern "C" {
/* Definitions of volume management */ /* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */ #if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct { typedef struct {
BYTE pd; /* Physical drive number */ BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
@@ -48,20 +49,19 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode (UTF-16) string */ #if FF_LFN_UNICODE && FF_USE_LFN /* Unicode (UTF-16) string */
#if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef WCHAR TCHAR; typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#define _INC_TCHAR
#endif #endif
#else /* ANSI/OEM string */ #else /* ANSI/OEM string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#define _INC_TCHAR
#endif #endif
#endif #endif
@@ -69,8 +69,8 @@ typedef char TCHAR;
/* Type of file size variables */ /* Type of file size variables */
#if _FS_EXFAT #if FF_FS_EXFAT
#if _USE_LFN == 0 #if !FF_USE_LFN
#error LFN must be enabled when enable exFAT #error LFN must be enabled when enable exFAT
#endif #endif
typedef QWORD FSIZE_t; typedef QWORD FSIZE_t;
@@ -80,36 +80,36 @@ typedef DWORD FSIZE_t;
/* File system object structure (FATFS) */ /* Filesystem object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* File system type (0:N/A) */ BYTE fs_type; /* Filesystem type (0:N/A) */
BYTE drv; /* Physical drive number */ BYTE pdrv; /* Physical drive number */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* File system mount ID */ WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */ WORD csize; /* Cluster size [sectors] */
#if _MAX_SS != _MIN_SS #if FF_MAX_SS != FF_MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif #endif
#if _USE_LFN != 0 #if FF_USE_LFN
WCHAR* lfnbuf; /* LFN working buffer */ WCHAR* lfnbuf; /* LFN working buffer */
#endif #endif
#if _FS_EXFAT #if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer */ BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif #endif
#if _FS_REENTRANT #if FF_FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */ FF_SYNC_t sobj; /* Identifier of sync object */
#endif #endif
#if !_FS_READONLY #if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */ DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */ DWORD free_clst; /* Number of free clusters */
#endif #endif
#if _FS_RPATH != 0 #if FF_FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */ DWORD cdir; /* Current directory start cluster (0:root) */
#if _FS_EXFAT #if FF_FS_EXFAT
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
@@ -122,52 +122,52 @@ typedef struct {
DWORD dirbase; /* Root directory base sector/cluster */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */ DWORD database; /* Data base sector */
DWORD winsect; /* Current sector appearing in the win[] */ DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS; } FATFS;
/* Object ID and allocation information (_FDID) */ /* Object ID and allocation information (FFOBJID) */
typedef struct { typedef struct {
FATFS* fs; /* Pointer to the owner file system object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Owner file system mount ID */ WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if _FS_EXFAT #if FF_FS_EXFAT
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */ DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */ DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */ DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
#endif #endif
#if _FS_LOCK != 0 #if FF_FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif #endif
} _FDID; } FFOBJID;
/* File object structure (FIL) */ /* File object structure (FIL) */
typedef struct { typedef struct {
_FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */ BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */ BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY #if !FF_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */ DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif #endif
#if _USE_FASTSEEK #if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif #endif
#if !_FS_TINY #if !FF_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */ BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif #endif
} FIL; } FIL;
@@ -176,16 +176,16 @@ typedef struct {
/* Directory object structure (DIR) */ /* Directory object structure (DIR) */
typedef struct { typedef struct {
_FDID obj; /* Object identifier */ FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */ DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */ DWORD clust; /* Current cluster */
DWORD sect; /* Current sector (0:Read operation has terminated) */ DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if _USE_LFN != 0 #if FF_USE_LFN
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif #endif
#if _USE_FIND #if FF_USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */ const TCHAR* pat; /* Pointer to the name matching pattern */
#endif #endif
} DIR; } DIR;
@@ -199,9 +199,9 @@ typedef struct {
WORD fdate; /* Modified date */ WORD fdate; /* Modified date */
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if _USE_LFN != 0 #if FF_USE_LFN
TCHAR altname[13]; /* Altenative file name */ TCHAR altname[13]; /* Altenative file name */
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ TCHAR fname[FF_MAX_LFN + 1]; /* Primary file name */
#else #else
TCHAR fname[13]; /* File name */ TCHAR fname[13]; /* File name */
#endif #endif
@@ -230,7 +230,7 @@ typedef enum {
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT; } FRESULT;
@@ -268,6 +268,7 @@ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
@@ -280,6 +281,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
#define f_rewind(fp) f_lseek((fp), 0) #define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0) #define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path) #define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF #ifndef EOF
#define EOF (-1) #define EOF (-1)
@@ -292,26 +294,27 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
/* Additional user defined functions */ /* Additional user defined functions */
/* RTC function */ /* RTC function */
#if !_FS_READONLY && !_FS_NORTC #if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void); DWORD get_fattime (void);
#endif #endif
/* Unicode support functions */ /* LFN support functions */
#if _USE_LFN != 0 /* Unicode - OEM code conversion */ #if FF_USE_LFN /* Code conversion (defined in unicode.c) */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ WCHAR ff_uni2oem (WCHAR uni, WORD cp); /* Unicode to OEM code conversion */
#if _USE_LFN == 3 /* Memory functions */ WCHAR ff_wtoupper (WCHAR uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */ void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */ void ff_memfree (void* mblock); /* Free memory block */
#endif #endif
#endif
/* Sync functions */ /* Sync functions */
#if _FS_REENTRANT #if FF_FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif #endif
@@ -358,4 +361,4 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
} }
#endif #endif
#endif /* _FATFS */ #endif /* FF_DEFINED */

View File

@@ -1,21 +1,21 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file / FatFs - Configuration file
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 68300 /* Revision ID */ #define FFCONF_DEF 87030 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_READONLY 0 #define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */ / and optional writing functions as well. */
#define _FS_MINIMIZE 0 #define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: All basic functions are enabled.
@@ -25,43 +25,42 @@
/ 3: f_lseek() function is removed in addition to 2. */ / 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 0 #define FF_USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/ f_printf().
/ /
/ 0: Disable string functions. / 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion. / 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 1 #define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define _USE_MKFS 0 #define FF_USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 0 #define FF_USE_FASTSEEK 0
/* This option switches fast seek function. (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
#define _USE_EXPAND 0 #define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */ /* This option switches f_expand function. (0:Disable or 1:Enable) */
#define _USE_CHMOD 0 #define FF_USE_CHMOD 0
/* This option switches attribute manipulation functions, f_chmod() and f_utime(). /* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define _USE_LABEL 0 #define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel(). /* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */ / (0:Disable or 1:Enable) */
#define _USE_FORWARD 0 #define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */ /* This option switches f_forward() function. (0:Disable or 1:Enable) */
@@ -69,11 +68,10 @@
/ Locale and Namespace Configurations / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _CODE_PAGE 437 #define FF_CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system. /* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure. / Incorrect code page setting can cause a file open failure.
/ /
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
/ 437 - U.S. / 437 - U.S.
/ 720 - Arabic / 720 - Arabic
/ 737 - Greek / 737 - Greek
@@ -95,47 +93,50 @@
/ 936 - Simplified Chinese (DBCS) / 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS) / 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS) / 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/ */
#define _USE_LFN 2 #define FF_USE_LFN 2
#define _MAX_LFN 255 #define FF_MAX_LFN 255
/* The _USE_LFN switches the support of long file name (LFN). /* The FF_USE_LFN switches the support for LFN (long file name).
/ /
/ 0: Disable support of LFN. _MAX_LFN has no effect. / 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK. / 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP. / 3: Enable LFN with dynamic working buffer on the HEAP.
/ /
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added / 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 / to the project. The working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. / additional 608 bytes at exFAT enabled. FF_MAX_LFN can be in range from 12 to 255.
/ It should be set 255 to support full featured LFN operations. / It should be set 255 to support full featured LFN operations.
/ When use stack for the working buffer, take care on stack overflow. When use heap / When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and / memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */ / ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0 #define FF_LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) /* 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. / when LFN is enabled. Also behavior of string I/O functions will be affected by
/ This option also affects behavior of string I/O functions. */ / this option. When LFN is not enabled, this option has no effect.
*/
#define _STRF_ENCODE 3 #define FF_STRF_ENCODE 3
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to /* When FF_LFN_UNICODE = 1 with LFN enabled, string I/O functions, f_gets(),
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/ /
/ 0: ANSI/OEM / 0: ANSI/OEM
/ 1: UTF-16LE / 1: UTF-16LE
/ 2: UTF-16BE / 2: UTF-16BE
/ 3: UTF-8 / 3: UTF-8
/ */
/ This option has no effect when _LFN_UNICODE == 0. */
#define _FS_RPATH 1 #define FF_FS_RPATH 1
/* This option configures support of relative path. /* This option configures support for relative path.
/ /
/ 0: Disable relative path and remove related functions. / 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available. / 1: Enable relative path. f_chdir() and f_chdrive() are available.
@@ -147,45 +148,45 @@
/ Drive/Volume Configurations / Drive/Volume Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _VOLUMES 2 #define FF_VOLUMES 2
/* Number of volumes (logical drives) to be used. (1-10) */ /* Number of volumes (logical drives) to be used. (1-10) */
#define _STR_VOLUME_ID 0 #define FF_STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID. /* FF_STR_VOLUME_ID switches string support for volume ID.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each / number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for / logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */ / the drive ID strings are: A-Z and 0-9. */
#define _MULTI_PARTITION 0 #define FF_MULTI_PARTITION 0
/* This option switches support of multi-partition on a physical drive. /* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive / By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted. / number and only an FAT volume found on the physical drive will be mounted.
/ When multi-partition is enabled (1), each logical drive number can be bound to / When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */ / funciton will be available. */
#define _MIN_SS 512 #define FF_MIN_SS 512
#define _MAX_SS 512 #define FF_MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024, /* This set of options configures the range of sector size to be supported. (512,
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some / harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to / for variable sector size mode and disk_ioctl() function needs to implement
/ the disk_ioctl() function. */ / GET_SECTOR_SIZE command. */
#define _USE_TRIM 0 #define FF_USE_TRIM 0
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the / To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */ / disk_ioctl() function. */
#define _FS_NOFSINFO 0 #define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this /* 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 / 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. / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
@@ -202,36 +203,36 @@
/ System Configurations / System Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0 #define FF_FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes. / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector / Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the file system object (FATFS) is used for the file data transfer. */ / buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define _FS_EXFAT 0 #define FF_FS_EXFAT 0
/* This option switches support of exFAT file system. (0:Disable or 1:Enable) /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) / When enable exFAT, also LFN needs to be enabled.
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ / Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define _FS_NORTC 1 #define FF_FS_NORTC 1
#define _NORTC_MON 1 #define FF_NORTC_MON 5
#define _NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define _NORTC_YEAR 2017 #define FF_NORTC_YEAR 2017
/* The option _FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_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 / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp / the timestamp function. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to get current time form real-time clock. _NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
/ _NORTC_MDAY and _NORTC_YEAR have no effect. / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ / These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define _FS_LOCK 0 #define FF_FS_LOCK 0
/* The option _FS_LOCK switches file lock function to control duplicated file open /* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1. / is 1.
/ /
/ 0: Disable file lock function. To avoid volume corruption, application program / 0: Disable file lock function. To avoid volume corruption, application program
@@ -241,23 +242,23 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
#define _FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define _FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define _SYNC_t HANDLE #define FF_SYNC_t HANDLE
/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function. / to the same volume is under control of this function.
/ /
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in / function, must be added to the project. Samples are available in
/ option/syscall.c. / option/syscall.c.
/ /
/ The _FS_TIMEOUT defines timeout period in unit of time tick. / The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */ / included somewhere in the scope of ff.h. */

171
source/fatfs/ffsystem.c Normal file
View File

@@ -0,0 +1,171 @@
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2017 */
/*------------------------------------------------------------------------*/
#include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
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); /* Free the memory block with POSIX API */
}
#endif
#if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
BYTE vol, /* Corresponding volume (logical drive number) */
FF_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */
// T_CSEM csem = {TA_TPRI,1,1};
// *sobj = acre_sem(&csem);
// return (int)(*sobj > 0);
/* uC/OS-II */
// OS_ERR err;
// *sobj = OSMutexCreate(0, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// *sobj = xSemaphoreCreateMutex();
// return (int)(*sobj != NULL);
/* CMSIS-RTOS */
// *sobj = osMutexCreate(Mutex + vol);
// return (int)(*sobj != NULL);
}
/*------------------------------------------------------------------------*/
/* 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 ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
/* Win32 */
return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// vSemaphoreDelete(sobj);
// return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* 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 */
FF_SYNC_t sobj /* Sync object to wait */
)
{
/* Win32 */
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
/* Win32 */
ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-II */
// OSMutexPost(sobj);
/* FreeRTOS */
// xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif

15566
source/fatfs/ffunicode.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
/* 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 */

View File

@@ -1,388 +0,0 @@
/*------------------------------------------------------------------------*/
/* 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

@@ -108,7 +108,7 @@ static bool checkFirm(u32 firmSize)
static inline u32 loadFirmFromStorage(FirmwareType firmType) static inline u32 loadFirmFromStorage(FirmwareType firmType)
{ {
const char *firmwareFiles[] = { static const char *firmwareFiles[] = {
"native.firm", "native.firm",
"twl.firm", "twl.firm",
"agb.firm", "agb.firm",
@@ -123,7 +123,7 @@ static inline u32 loadFirmFromStorage(FirmwareType firmType)
"cetk_sysupdater" "cetk_sysupdater"
}; };
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200); u32 firmSize = fileRead(firm, firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
if(!firmSize) return 0; if(!firmSize) return 0;
@@ -137,7 +137,7 @@ static inline u32 loadFirmFromStorage(FirmwareType firmType)
u8 cetk[0xA50]; u8 cetk[0xA50];
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk)) if(fileRead(cetk, cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk))
error("The cetk is missing or corrupted."); error("The cetk is missing or corrupted.");
firmSize = decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize); firmSize = decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize);
@@ -152,16 +152,42 @@ static inline u32 loadFirmFromStorage(FirmwareType firmType)
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode) u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
{ {
u32 firmVersion,
firmSize;
bool ctrNandError = isSdMode && !mountFs(false, false);
if(!ctrNandError)
{
//Load FIRM from CTRNAND //Load FIRM from CTRNAND
u32 firmVersion = firmRead(firm, (u32)*firmType); firmVersion = firmRead(firm, (u32)*firmType);
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM."); if(firmVersion == 0xFFFFFFFF) ctrNandError = true;
else
{
firmSize = decryptExeFs((Cxi *)firm);
u32 firmSize = decryptExeFs((Cxi *)firm); if(!firmSize || !checkFirm(firmSize)) ctrNandError = true;
}
}
if(!firmSize) error("Failed to decrypt the CTRNAND FIRM."); bool loadedFromStorage = false;
if(!checkFirm(firmSize)) error("The CTRNAND FIRM is invalid or corrupted."); if(loadFromStorage || ctrNandError)
{
u32 result = loadFirmFromStorage(*firmType);
if(result != 0)
{
loadedFromStorage = true;
firmSize = result;
}
else if(ctrNandError) error("Unable to mount CTRNAND or load the CTRNAND FIRM.\nPlease use an external one.");
}
//Check that the FIRM is right for the console from the ARM9 section address
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
if(!ISN3DS && *firmType == NATIVE_FIRM && firm->section[0].address == (u8 *)0x1FF80000) if(!ISN3DS && *firmType == NATIVE_FIRM && firm->section[0].address == (u8 *)0x1FF80000)
{ {
@@ -173,23 +199,6 @@ u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadF
*firmType = NATIVE_FIRM1X2X; *firmType = NATIVE_FIRM1X2X;
} }
bool loadedFromStorage = false;
if(loadFromStorage)
{
u32 result = loadFirmFromStorage(*firmType);
if(result != 0)
{
loadedFromStorage = true;
firmSize = result;
}
}
//Check that the FIRM is right for the console from the ARM9 section address
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
error("The %s FIRM is not for this console.", loadedFromStorage ? "external" : "CTRNAND");
if(loadedFromStorage || ISDEVUNIT) if(loadedFromStorage || ISDEVUNIT)
{ {
firmVersion = 0xFFFFFFFF; firmVersion = 0xFFFFFFFF;
@@ -335,7 +344,7 @@ static inline void mergeSection0(FirmwareType firmType, u32 firmVersion, bool lo
} }
} }
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch) u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isFirmProtEnabled, bool isSafeMode, bool doUnitinfoPatch)
{ {
u8 *arm9Section = (u8 *)firm + firm->section[2].offset, u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
*arm11Section1 = (u8 *)firm + firm->section[1].offset; *arm11Section1 = (u8 *)firm + firm->section[1].offset;
@@ -376,7 +385,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion); if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address, firmVersion);
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH //Apply FIRM0/1 writes patches on SysNAND to protect A9LH
else ret += patchFirmWrites(process9Offset, process9Size); else if(isFirmProtEnabled) ret += patchFirmWrites(process9Offset, process9Size);
//Apply firmlaunch patches //Apply firmlaunch patches
ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr); ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
@@ -403,7 +412,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address); ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
ret += patchKernel9Panic(arm9Section, kernel9Size); ret += patchKernel9Panic(arm9Section, kernel9Size);
if(CONFIG(PATCHACCESS)) ret += patchP9AccessChecks(process9Offset, process9Size); ret += patchP9AccessChecks(process9Offset, process9Size);
mergeSection0(NATIVE_FIRM, firmVersion, loadFromStorage); mergeSection0(NATIVE_FIRM, firmVersion, loadFromStorage);
firm->section[0].size = 0; firm->section[0].size = 0;

View File

@@ -31,7 +31,7 @@
u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode); u32 loadNintendoFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
void loadHomebrewFirm(u32 pressed); void loadHomebrewFirm(u32 pressed);
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch); u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isFirmProtEnabled, bool isSafeMode, bool doUnitinfoPatch);
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch); u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch); u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
u32 patch1x2xNativeAndSafeFirm(void); u32 patch1x2xNativeAndSafeFirm(void);

View File

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

View File

@@ -51,8 +51,7 @@ static bool switchToMainDir(bool isSd)
case FR_OK: case FR_OK:
return true; return true;
case FR_NO_PATH: case FR_NO_PATH:
f_mkdir(mainDir); return f_mkdir(mainDir) == FR_OK && switchToMainDir(isSd);
return switchToMainDir(isSd);
default: default:
return false; return false;
} }
@@ -67,6 +66,7 @@ bool mountFs(bool isSd, bool switchToCtrNand)
u32 fileRead(void *dest, const char *path, u32 maxSize) u32 fileRead(void *dest, const char *path, u32 maxSize)
{ {
FIL file; FIL file;
FRESULT result = FR_OK;
u32 ret = 0; u32 ret = 0;
if(f_open(&file, path, FA_READ) != FR_OK) return ret; if(f_open(&file, path, FA_READ) != FR_OK) return ret;
@@ -74,10 +74,10 @@ u32 fileRead(void *dest, const char *path, u32 maxSize)
u32 size = f_size(&file); u32 size = f_size(&file);
if(dest == NULL) ret = size; if(dest == NULL) ret = size;
else if(size <= maxSize) else if(size <= maxSize)
f_read(&file, dest, size, (unsigned int *)&ret); result = f_read(&file, dest, size, (unsigned int *)&ret);
f_close(&file); result |= f_close(&file);
return ret; return result == FR_OK ? ret : 0;
} }
u32 getFileSize(const char *path) u32 getFileSize(const char *path)
@@ -88,17 +88,18 @@ u32 getFileSize(const char *path)
bool fileWrite(const void *buffer, const char *path, u32 size) bool fileWrite(const void *buffer, const char *path, u32 size)
{ {
FIL file; FIL file;
FRESULT result;
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS)) switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
{ {
case FR_OK: case FR_OK:
{ {
unsigned int written; unsigned int written;
f_write(&file, buffer, size, &written); result = f_write(&file, buffer, size, &written);
f_truncate(&file); if(result == FR_OK) result = f_truncate(&file);
f_close(&file); result |= f_close(&file);
return (u32)written == size; return result == FR_OK && (u32)written == size;
} }
case FR_NO_PATH: case FR_NO_PATH:
for(u32 i = 1; path[i] != 0; i++) for(u32 i = 1; path[i] != 0; i++)
@@ -107,18 +108,18 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
char folder[i + 1]; char folder[i + 1];
memcpy(folder, path, i); memcpy(folder, path, i);
folder[i] = 0; folder[i] = 0;
f_mkdir(folder); result = f_mkdir(folder);
} }
return fileWrite(buffer, path, size); return result == FR_OK && fileWrite(buffer, path, size);
default: default:
return false; return false;
} }
} }
void fileDelete(const char *path) bool fileDelete(const char *path)
{ {
f_unlink(path); return f_unlink(path) == FR_OK;
} }
bool findPayload(char *path, u32 pressed) bool findPayload(char *path, u32 pressed)
@@ -181,9 +182,7 @@ bool payloadMenu(char *path)
payloadNum++; payloadNum++;
} }
f_closedir(&dir); if(f_closedir(&dir) != FR_OK || !payloadNum) return false;
if(!payloadNum) return false;
u32 pressed = 0, u32 pressed = 0,
selectedPayload = 0; selectedPayload = 0;
@@ -205,9 +204,9 @@ bool payloadMenu(char *path)
{ {
do do
{ {
pressed = waitInput(true); pressed = waitInput(true) & MENU_BUTTONS;
} }
while(!(pressed & MENU_BUTTONS)); while(!pressed);
u32 oldSelectedPayload = selectedPayload; u32 oldSelectedPayload = selectedPayload;
@@ -251,7 +250,7 @@ bool payloadMenu(char *path)
u32 firmRead(void *dest, u32 firmType) u32 firmRead(void *dest, u32 firmType)
{ {
const char *firmFolders[][2] = {{"00000002", "20000002"}, static const char *firmFolders[][2] = {{"00000002", "20000002"},
{"00000102", "20000102"}, {"00000102", "20000102"},
{"00000202", "20000202"}, {"00000202", "20000202"},
{"00000003", "20000003"}, {"00000003", "20000003"},
@@ -281,9 +280,7 @@ u32 firmRead(void *dest, u32 firmType)
if(tempVersion < firmVersion) firmVersion = tempVersion; if(tempVersion < firmVersion) firmVersion = tempVersion;
} }
f_closedir(&dir); if(f_closedir(&dir) != FR_OK || firmVersion == 0xFFFFFFFF) goto exit;
if(firmVersion == 0xFFFFFFFF) goto exit;
//Complete the string with the .app name //Complete the string with the .app name
sprintf(path, "%s/%08x.app", folderPath, firmVersion); sprintf(path, "%s/%08x.app", folderPath, firmVersion);

View File

@@ -34,7 +34,7 @@ bool mountFs(bool isSd, bool switchToCtrNand);
u32 fileRead(void *dest, const char *path, u32 maxSize); u32 fileRead(void *dest, const char *path, u32 maxSize);
u32 getFileSize(const char *path); u32 getFileSize(const char *path);
bool fileWrite(const void *buffer, const char *path, u32 size); bool fileWrite(const void *buffer, const char *path, u32 size);
void fileDelete(const char *path); bool fileDelete(const char *path);
bool findPayload(char *path, u32 pressed); bool findPayload(char *path, u32 pressed);
bool payloadMenu(char *path); bool payloadMenu(char *path);
u32 firmRead(void *dest, u32 firmType); u32 firmRead(void *dest, u32 firmType);

View File

@@ -37,24 +37,34 @@
#include "crypto.h" #include "crypto.h"
#include "memory.h" #include "memory.h"
#include "screen.h" #include "screen.h"
#include "fatfs/sdmmc/sdmmc.h"
extern CfgData configData; extern CfgData configData;
extern ConfigurationStatus needConfig; extern ConfigurationStatus needConfig;
extern FirmwareSource firmSource; extern FirmwareSource firmSource;
bool isFirmlaunch = false, bool isSdMode;
isSdMode;
u16 launchedPath[41]; u16 launchedPath[41];
BootType bootType;
void main(int argc, char **argv, u32 magicWord) void main(int argc, char **argv, u32 magicWord)
{ {
bool isSafeMode = false, bool isFirmProtEnabled,
isNoForceFlagSet = false; isSafeMode = false,
isNoForceFlagSet = false,
isNtrBoot;
FirmwareType firmType; FirmwareType firmType;
FirmwareSource nandType; FirmwareSource nandType;
const vu8 *bootMediaStatus = (const vu8 *)0x1FFFE00C;
const vu32 *bootPartitionsStatus = (const vu32 *)0x1FFFE010;
if((magicWord & 0xFFFF) == 0xBEEF && argc >= 1) //Normal boot //Shell closed, no error booting NTRCARD, NAND paritions not even considered
isNtrBoot = bootMediaStatus[3] == 2 && !bootMediaStatus[1] && !bootPartitionsStatus[0] && !bootPartitionsStatus[1];
if((magicWord & 0xFFFF) == 0xBEEF && argc >= 1) //Normal (B9S) boot
{ {
bootType = isNtrBoot ? B9SNTR : B9S;
u32 i; u32 i;
for(i = 0; i < 40 && argv[0][i] != 0; i++) //Copy and convert the path to UTF-16 for(i = 0; i < 40 && argv[0][i] != 0; i++) //Copy and convert the path to UTF-16
launchedPath[i] = argv[0][i]; launchedPath[i] = argv[0][i];
@@ -62,21 +72,39 @@ void main(int argc, char **argv, u32 magicWord)
} }
else if(magicWord == 0xBABE && argc == 2) //Firmlaunch else if(magicWord == 0xBABE && argc == 2) //Firmlaunch
{ {
bootType = FIRMLAUNCH;
u32 i; u32 i;
u16 *p = (u16 *)argv[0]; u16 *p = (u16 *)argv[0];
for(i = 0; i < 40 && p[i] != 0; i++) for(i = 0; i < 40 && p[i] != 0; i++)
launchedPath[i] = p[i]; launchedPath[i] = p[i];
launchedPath[i] = 0; launchedPath[i] = 0;
}
isFirmlaunch = true; else if(magicWord == 0xB002) //FIRM/NTRCARD boot
{
if(isNtrBoot) bootType = NTR;
else
{
const char *path;
if(!((vu8 *)bootPartitionsStatus)[2])
{
bootType = FIRM0;
path = "firm0:";
} }
else else
{ {
static const char argv[] = "firm0:"; bootType = FIRM1;
for(u32 i = 0; i < sizeof(argv); i++) //Copy and convert the path to UTF-16 path = "firm1:";
launchedPath[i] = argv[i];
} }
for(u32 i = 0; i < 7; i++) //Copy and convert the path to UTF-16
launchedPath[i] = path[i];
}
setupKeyslots();
}
else error("Launched using an unsupported loader.");
if(memcmp(launchedPath, u"sdmc", 8) == 0) if(memcmp(launchedPath, u"sdmc", 8) == 0)
{ {
if(!mountFs(true, false)) error("Failed to mount SD."); if(!mountFs(true, false)) error("Failed to mount SD.");
@@ -84,17 +112,21 @@ void main(int argc, char **argv, u32 magicWord)
} }
else if(memcmp(launchedPath, u"nand", 8) == 0) else if(memcmp(launchedPath, u"nand", 8) == 0)
{ {
firmSource = FIRMWARE_SYSNAND;
if(!mountFs(false, true)) error("Failed to mount CTRNAND."); if(!mountFs(false, true)) error("Failed to mount CTRNAND.");
isSdMode = false; isSdMode = false;
} }
else if(memcmp(launchedPath, u"firm", 8) == 0) else if(bootType == NTR || memcmp(launchedPath, u"firm", 8) == 0)
{ {
setupKeyslots();
if(mountFs(true, false)) isSdMode = true; if(mountFs(true, false)) isSdMode = true;
else if(mountFs(false, true)) isSdMode = false; else if(mountFs(false, true)) isSdMode = false;
else error("Failed to mount SD and CTRNAND."); else error("Failed to mount SD and CTRNAND.");
if(bootType == NTR)
{
while(HID_PAD & NTRBOOT_BUTTONS);
loadHomebrewFirm(0);
mcuPowerOff();
}
} }
else else
{ {
@@ -112,7 +144,7 @@ void main(int argc, char **argv, u32 magicWord)
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION; needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
//Determine if this is a firmlaunch boot //Determine if this is a firmlaunch boot
if(isFirmlaunch) if(bootType == FIRMLAUNCH)
{ {
if(needConfig == CREATE_CONFIGURATION) mcuPowerOff(); if(needConfig == CREATE_CONFIGURATION) mcuPowerOff();
@@ -131,6 +163,7 @@ void main(int argc, char **argv, u32 magicWord)
nandType = (FirmwareSource)BOOTCFG_NAND; nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM; firmSource = (FirmwareSource)BOOTCFG_FIRM;
isFirmProtEnabled = !BOOTCFG_NTRCARDBOOT;
goto boot; goto boot;
} }
@@ -139,6 +172,7 @@ void main(int argc, char **argv, u32 magicWord)
installArm9Handlers(); installArm9Handlers();
firmType = NATIVE_FIRM; firmType = NATIVE_FIRM;
isFirmProtEnabled = bootType != NTR;
//Get pressed buttons //Get pressed buttons
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
@@ -146,7 +180,6 @@ void main(int argc, char **argv, u32 magicWord)
//If it's a MCU reboot, try to force boot options //If it's a MCU reboot, try to force boot options
if(CFG_BOOTENV && needConfig != CREATE_CONFIGURATION) if(CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
{ {
//Always force a SysNAND boot when quitting AGB_FIRM //Always force a SysNAND boot when quitting AGB_FIRM
if(CFG_BOOTENV == 7) if(CFG_BOOTENV == 7)
{ {
@@ -173,7 +206,7 @@ void main(int argc, char **argv, u32 magicWord)
u32 pinMode = MULTICONFIG(PIN); u32 pinMode = MULTICONFIG(PIN);
bool pinExists = pinMode != 0 && verifyPin(pinMode); bool pinExists = pinMode != 0 && verifyPin(pinMode);
//If no configuration file exists or SELECT is held, load configuration menu //If no configuration file exists or SELECT is held or if booted from NTRCARD, load configuration menu
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT); bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT);
if(shouldLoadConfigMenu) if(shouldLoadConfigMenu)
@@ -205,13 +238,15 @@ void main(int argc, char **argv, u32 magicWord)
if(splashMode == 1 && loadSplash()) pressed = HID_PAD; if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
bool autoBootEmu = CONFIG(AUTOBOOTEMU);
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
{ {
loadHomebrewFirm(0); loadHomebrewFirm(0);
pressed = HID_PAD; pressed = HID_PAD;
} }
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || else if((((pressed & SINGLE_PAYLOAD_BUTTONS) || (!autoBootEmu && (pressed & DPAD_BUTTONS))) && !(pressed & (BUTTON_L1 | BUTTON_R1))) ||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed); (((pressed & L_PAYLOAD_BUTTONS) || (autoBootEmu && (pressed & DPAD_BUTTONS))) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed);
if(splashMode == 2) loadSplash(); if(splashMode == 2) loadSplash();
@@ -235,7 +270,7 @@ void main(int argc, char **argv, u32 magicWord)
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
with their own FIRM */ with their own FIRM */
else firmSource = nandType = (CONFIG(AUTOBOOTEMU) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND; else firmSource = nandType = (autoBootEmu == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
@@ -271,20 +306,20 @@ boot:
{ {
locateEmuNand(&nandType); locateEmuNand(&nandType);
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND; if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
else if((*(vu16 *)(SDMMC_BASE + REG_SDSTATUS0) & TMIO_STAT0_WRPROTECT) == 0) //Make sure the SD card isn't write protected
error("The SD card is locked, EmuNAND can not be used.\nPlease turn the write protection switch off.");
} }
//Same if we're using EmuNAND as the FIRM source //Same if we're using EmuNAND as the FIRM source
else if(firmSource != FIRMWARE_SYSNAND) else if(firmSource != FIRMWARE_SYSNAND)
locateEmuNand(&firmSource); locateEmuNand(&firmSource);
if(!isFirmlaunch) if(bootType != FIRMLAUNCH)
{ {
configData.bootConfig = ((u32)isNoForceFlagSet << 6) | ((u32)firmSource << 3) | (u32)nandType; configData.bootConfig = ((bootType == NTR ? 1 : 0) << 7) | ((u32)isNoForceFlagSet << 6) | ((u32)firmSource << 3) | (u32)nandType;
writeConfig(false); writeConfig(false);
} }
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES); bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
u32 firmVersion = loadNintendoFirm(&firmType, firmSource, loadFromStorage, isSafeMode); u32 firmVersion = loadNintendoFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
@@ -293,7 +328,7 @@ boot:
switch(firmType) switch(firmType)
{ {
case NATIVE_FIRM: case NATIVE_FIRM:
res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isSafeMode, doUnitinfoPatch); res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isFirmProtEnabled, isSafeMode, doUnitinfoPatch);
break; break;
case TWL_FIRM: case TWL_FIRM:
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch); res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
@@ -310,6 +345,6 @@ boot:
if(res != 0) error("Failed to apply %u FIRM patch(es).", res); if(res != 0) error("Failed to apply %u FIRM patch(es).", res);
if(!isFirmlaunch) deinitScreens(); if(bootType != FIRMLAUNCH) deinitScreens();
launchFirm(0, NULL); launchFirm(0, NULL);
} }

View File

@@ -454,7 +454,9 @@ u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
if(temp == NULL) return 1; if(temp == NULL) return 1;
u32 *off = (u32 *)(temp - 0xA); u32 *off;
for(off = (u32 *)(temp - 2); *off != 0xE5801000; off--); //Until str r1, [r0]
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
{ {
@@ -491,7 +493,15 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL)
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
*addr = 0xE12FFF7F;
/*
mov r8, sp
bkpt 0xffff
*/
addr[0] = 0xE1A0800D;
addr[1] = 0xE12FFF7F;
*(vu32 *)0x01FF8004 = arm9SvcTable[0x3C]; //BreakPtr
return 0; return 0;
} }

View File

@@ -146,11 +146,20 @@ bool verifyPin(u32 pinMode)
initScreens(); initScreens();
swapFramebuffers(true);
drawString(true, 10, 10, COLOR_TITLE, "Enter the PIN using ABXY and the DPad to proceed"); drawString(true, 10, 10, COLOR_TITLE, "Enter the PIN using ABXY and the DPad to proceed");
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press START to shutdown, SELECT to clear"); drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press START to shutdown, SELECT to clear");
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", lengthBlock[0]); drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", lengthBlock[0]);
bool isBottomSplashValid = getFileSize("splashpin.bin") == SCREEN_BOTTOM_FBSIZE;
if(isBottomSplashValid)
{
isBottomSplashValid = fileRead(fbs[0].bottom, "splashpin.bin", SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
}
else
{
static const char *messageFile = "pinmessage.txt"; static const char *messageFile = "pinmessage.txt";
char message[801]; char message[801];
@@ -161,6 +170,8 @@ bool verifyPin(u32 pinMode)
message[messageSize] = 0; message[messageSize] = 0;
drawString(false, 10, 10, COLOR_WHITE, message); drawString(false, 10, 10, COLOR_WHITE, message);
} }
}
swapFramebuffers(false);
//Pad to AES block length with zeroes //Pad to AES block length with zeroes
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0}; __attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};

View File

@@ -107,10 +107,13 @@ void initScreens(void)
} }
else updateBrightness(MULTICONFIG(BRIGHTNESS)); else updateBrightness(MULTICONFIG(BRIGHTNESS));
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
invokeArm11Function(SETUP_FRAMEBUFFERS);
clearScreens(true);
needToSetup = false; needToSetup = false;
} }
clearScreens(false); clearScreens(false);
clearScreens(true);
swapFramebuffers(false); swapFramebuffers(false);
} }

View File

@@ -49,11 +49,12 @@ struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; u8 *bottom;
} __attribute__((packed)); };
typedef enum typedef enum
{ {
INIT_SCREENS = 0, INIT_SCREENS = 0,
SETUP_FRAMEBUFFERS,
CLEAR_SCREENS, CLEAR_SCREENS,
SWAP_FRAMEBUFFERS, SWAP_FRAMEBUFFERS,
UPDATE_BRIGHTNESS, UPDATE_BRIGHTNESS,

View File

@@ -27,9 +27,23 @@
.global _start .global _start
_start: _start:
@ Disable interrupts and switch to supervisor mode (also clear flags) @ Disable interrupts and switch to supervisor mode (also clear flags)
mov r4, #0x13 msr cpsr_cxsf, #0xD3
orr r4, #0x1C0
msr cpsr_cxsf, r4 @ Check if r0-r2 are 0 (r0-sp are supposed to be 0), and for regions 0, 5 and 7 of the MPU config
@ This is not foolproof but should work well enough
cmp r0, #0
cmpeq r1, #0
cmpeq r2, #0
ldreq r4, =0x20000035
mrceq p15, 0, r5, c6, c0, 0
cmpeq r4, r5
mrceq p15, 0, r5, c6, c5, 0
ldreq r4, =0x07FF801D
cmpeq r4, r5
mrceq p15, 0, r5, c6, c7, 0
ldreq r4, =0x1FFFE019
cmpeq r4, r5
ldreq r2, =0xB002
mov r9, r0 mov r9, r0
mov r10, r1 mov r10, r1

View File

@@ -114,8 +114,19 @@ typedef enum FirmwareType
NATIVE_FIRM1X2X NATIVE_FIRM1X2X
} FirmwareType; } FirmwareType;
extern bool isFirmlaunch, typedef enum bootType
isSdMode; {
B9S = 0,
B9SNTR,
FIRM0,
FIRM1,
FIRMLAUNCH,
NTR
} BootType;
extern bool isSdMode;
extern BootType bootType;
extern u16 launchedFirmTidLow[8]; extern u16 launchedFirmTidLow[8];
extern u16 launchedPath[41]; extern u16 launchedPath[41];

View File

@@ -71,6 +71,7 @@ u32 waitInput(bool isMenu)
u64 initialValue = 0ULL; u64 initialValue = 0ULL;
u32 key, u32 key,
oldKey = HID_PAD; oldKey = HID_PAD;
bool shouldShellShutdown = bootType != B9SNTR && bootType != NTR;
if(isMenu) if(isMenu)
{ {
@@ -85,7 +86,8 @@ u32 waitInput(bool isMenu)
if(!key) if(!key)
{ {
if((i2cReadRegister(I2C_DEV_MCU, 0x10) & 1)== 1) mcuPowerOff(); if((!(i2cReadRegister(I2C_DEV_MCU, 0xF) & 2) && shouldShellShutdown) ||
(i2cReadRegister(I2C_DEV_MCU, 0x10) & 1) == 1) mcuPowerOff();
oldKey = 0; oldKey = 0;
dPadDelay = 0; dPadDelay = 0;
continue; continue;
@@ -104,7 +106,10 @@ u32 waitInput(bool isMenu)
void mcuPowerOff(void) void mcuPowerOff(void)
{ {
if(!isFirmlaunch && ARESCREENSINITIALIZED) clearScreens(false); if(bootType != FIRMLAUNCH && ARESCREENSINITIALIZED) clearScreens(false);
//Shutdown LCD
if(ARESCREENSINITIALIZED) i2cWriteRegister(I2C_DEV_MCU, 0x22, 1 << 0);
//Ensure that all memory transfers have completed and that the data cache has been flushed //Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireDCache(); flushEntireDCache();
@@ -131,7 +136,7 @@ void error(const char *fmt, ...)
vsprintf(buf, fmt, args); vsprintf(buf, fmt, args);
va_end(args); va_end(args);
if(!isFirmlaunch) if(bootType != FIRMLAUNCH)
{ {
initScreens(); initScreens();

View File

@@ -20,7 +20,7 @@ LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math $(INCLUDE) -DARM11 -D_3DS CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -O2 -ffast-math $(INCLUDE) -DARM11 -D_3DS
LDFLAGS := -specs=3dsx.specs $(ASFLAGS) -Wl,--section-start,.text=0x14000000 LDFLAGS := -specs=3dsx.specs $(ASFLAGS) -Wl,--section-start,.text=0x14000000
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \

View File

@@ -64,17 +64,20 @@ _start:
load r3, customPath load r3, customPath
pathRedir_1: pathRedir_1:
ldrb r2, [r3], #1 ldrb r2, [r3], #1
strh r2, [r0], #2
cmp r2, #0 cmp r2, #0
strneh r2, [r0], #2
bne pathRedir_1 bne pathRedir_1
sub r0, r0, #2
pathRedir_2: pathRedir_2:
ldrh r2, [r1], #2 ldrh r2, [r1], #2
cmp r2, #0x3A ; ':' cmp r2, #0x3A ; ':'
bne pathRedir_2 bne pathRedir_2
; Skip a slash if there are two after the mountpoint,
; as some games mistakenly have those
ldrh r3, [r1, #2]
cmp r3, #0x2F ; '/'
pathRedir_3: pathRedir_3:
ldrh r2, [r1], #2 ldrh r2, [r1], #2
strh r2, [r0], #2 strneh r2, [r0], #2
cmp r2, #0 cmp r2, #0
bne pathRedir_3 bne pathRedir_3
ldmfd sp!, {r0-r3} ldmfd sp!, {r0-r3}

View File

@@ -11,6 +11,9 @@
#define MAX_SESSIONS 1 #define MAX_SESSIONS 1
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) #define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
u32 config, multiConfig, bootConfig;
bool isN3DS, isSafeMode, isSdMode;
const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00}; const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00};
typedef struct typedef struct
@@ -30,6 +33,28 @@ static u64 g_cached_prog_handle;
static exheader_header g_exheader; static exheader_header g_exheader;
static char g_ret_buf[1024]; static char g_ret_buf[1024];
static inline void loadCFWInfo(void)
{
s64 out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
config = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT);
multiConfig = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT);
bootConfig = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT);
isN3DS = (bool)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT);
isSafeMode = (bool)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
isSdMode = (bool)out;
IFile file;
if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
}
static int lzss_decompress(u8 *end) static int lzss_decompress(u8 *end)
{ {
unsigned int v1; // r1@2 unsigned int v1; // r1@2
@@ -116,6 +141,8 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
u64 size; u64 size;
u64 total; u64 total;
if(!CONFIG(PATCHGAMES) || !loadTitleCodeSection(progid, (u8 *)shared->text_addr, (u64)shared->total_size << 12))
{
archivePath.type = PATH_BINARY; archivePath.type = PATH_BINARY;
archivePath.data = &prog_handle; archivePath.data = &prog_handle;
archivePath.size = 8; archivePath.size = 8;
@@ -155,6 +182,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
{ {
lzss_decompress((u8 *)shared->text_addr + size); lzss_decompress((u8 *)shared->text_addr + size);
} }
}
u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8); u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8);
@@ -212,7 +240,9 @@ static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle)
exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480; exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480;
// Tweak 3dsx placeholder title exheader // Tweak 3dsx placeholder title exheader
if (nbSection0Modules == 6 && exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID) if (nbSection0Modules == 6)
{
if(exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID)
{ {
Handle hbldr = 0; Handle hbldr = 0;
res = HBLDR_Init(&hbldr); res = HBLDR_Init(&hbldr);
@@ -229,6 +259,14 @@ static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle)
} }
} }
} }
u64 originalProgId = exheader->arm11systemlocalcaps.programid;
if(CONFIG(PATCHGAMES) && loadTitleExheader(exheader->arm11systemlocalcaps.programid, exheader))
{
exheader->arm11systemlocalcaps.programid = originalProgId;
exheader->accessdesc.arm11systemlocalcaps.programid = originalProgId;
}
}
} }
return res; return res;
@@ -586,6 +624,8 @@ int main()
svcBreak(USERBREAK_ASSERT); svcBreak(USERBREAK_ASSERT);
} }
loadCFWInfo();
g_active_handles = 2; g_active_handles = 2;
g_cached_prog_handle = 0; g_cached_prog_handle = 0;
index = 1; index = 1;

View File

@@ -9,6 +9,14 @@ void memcpy(void *dest, const void *src, u32 size)
destc[i] = srcc[i]; destc[i] = srcc[i];
} }
void memset32(void *dest, u32 filler, u32 size)
{
u32 *dest32 = (u32 *)dest;
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 u8 *buf1c = (const u8 *)buf1, const u8 *buf1c = (const u8 *)buf1,

View File

@@ -3,5 +3,6 @@
#include <3ds/types.h> #include <3ds/types.h>
void memcpy(void *dest, const void *src, u32 size); void memcpy(void *dest, const void *src, u32 size);
void memset32(void *dest, u32 filler, u32 size);
int memcmp(const void *buf1, const void *buf2, u32 size); int memcmp(const void *buf1, const void *buf2, u32 size);
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);

View File

@@ -3,12 +3,8 @@
#include "memory.h" #include "memory.h"
#include "strings.h" #include "strings.h"
#include "fsldr.h" #include "fsldr.h"
#include "ifile.h"
#include "../build/bundled.h" #include "../build/bundled.h"
static u32 config, multiConfig, bootConfig;
static bool isN3DS, isSafeMode, isSdMode;
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count) static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count)
{ {
u32 i; u32 i;
@@ -32,7 +28,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s3
return i; return i;
} }
static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags) Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
{ {
FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path}, FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path},
archivePath = {PATH_EMPTY, 1, (u8 *)""}; archivePath = {PATH_EMPTY, 1, (u8 *)""};
@@ -73,32 +69,6 @@ static u32 checkLumaDir(const char *path)
return dirCheck(archiveId, path) ? archiveId : 0; return dirCheck(archiveId, path) ? archiveId : 0;
} }
static inline void loadCFWInfo(void)
{
static bool infoLoaded = false;
s64 out;
if(infoLoaded) return;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
config = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT);
multiConfig = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT);
bootConfig = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT);
isN3DS = (bool)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT);
isSafeMode = (bool)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
isSdMode = (bool)out;
IFile file;
if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
infoLoaded = true;
}
static inline bool secureInfoExists(void) static inline bool secureInfoExists(void)
{ {
static bool exists = false; static bool exists = false;
@@ -353,7 +323,7 @@ exit:
return ret; return ret;
} }
static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size) bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
{ {
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/code.bin" /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/code.bin"
If it exists it should be a decrypted and decompressed binary code file */ If it exists it should be a decrypted and decompressed binary code file */
@@ -363,22 +333,60 @@ static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
IFile file; IFile file;
if(!openLumaFile(&file, path)) return true; if(!openLumaFile(&file, path)) return false;
bool ret;
u64 fileSize; u64 fileSize;
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = false; if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) goto error;
else else
{ {
u64 total; u64 total;
ret = R_SUCCEEDED(IFile_Read(&file, &total, code, fileSize)) && total == fileSize; if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) goto error;
} }
IFile_Close(&file); IFile_Close(&file);
return ret; return true;
error:
IFile_Close(&file);
svcBreak(USERBREAK_ASSERT);
while(true);
}
bool loadTitleExheader(u64 progId, exheader_header *exheader)
{
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/exheader.bin"
If it exists it should be a decrypted exheader */
char path[] = "/luma/titles/0000000000000000/exheader.bin";
progIdToStr(path + 28, progId);
IFile file;
if(!openLumaFile(&file, path)) return false;
u64 fileSize;
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize != sizeof(exheader_header)) goto error;
else
{
u64 total;
if(R_FAILED(IFile_Read(&file, &total, exheader, fileSize)) || total != fileSize) goto error;
}
IFile_Close(&file);
return true;
error:
IFile_Close(&file);
svcBreak(USERBREAK_ASSERT);
while(true);
} }
static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8 *languageId, u8 *countryId, u8 *stateId) static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8 *languageId, u8 *countryId, u8 *stateId)
@@ -570,8 +578,6 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress) void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress)
{ {
loadCFWInfo();
if(progId == 0x0004003000008F02LL || //USA Home Menu if(progId == 0x0004003000008F02LL || //USA Home Menu
progId == 0x0004003000008202LL || //JPN Home Menu progId == 0x0004003000008202LL || //JPN Home Menu
progId == 0x0004003000009802LL || //EUR Home Menu progId == 0x0004003000009802LL || //EUR Home Menu
@@ -644,22 +650,6 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
off[1] = 0xE12FFF1E; //bx lr off[1] = 0xE12FFF1E; //bx lr
} }
else if(progId == 0x0004013000003202LL) //FRIENDS
{
static const u8 pattern[] = {
0x42, 0xE0, 0x1E, 0xFF
};
u8 mostRecentFpdVer = 10;
u8 *off = memsearch(code, pattern, textSize, sizeof(pattern));
if(off == NULL) goto error;
//Allow online access to work with old friends modules
if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
}
else if((progId == 0x0004001000021000LL || //USA MSET else if((progId == 0x0004001000021000LL || //USA MSET
progId == 0x0004001000020000LL || //JPN MSET progId == 0x0004001000020000LL || //JPN MSET
progId == 0x0004001000022000LL || //EUR MSET progId == 0x0004001000022000LL || //EUR MSET
@@ -755,6 +745,25 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
} }
} }
if(progVer > 0x12)
{
static const u8 pattern[] = {
0x00, 0xB1, 0x15, 0x00
};
u8 *roStart = code + ((textSize + 4095) & 0xFFFFF000),
*start = memsearch(roStart, pattern, roSize, sizeof(pattern));
if(start == NULL) goto error;
start++;
u8 *end;
for(end = start + 8; *(u32 *)end != 0xCC010000; end += 8)
if(end >= roStart + roSize - 12) goto error;
memset32(start, 0, end - start);
}
s64 nbSection0Modules; s64 nbSection0Modules;
svcGetSystemInfo(&nbSection0Modules, 26, 0); svcGetSystemInfo(&nbSection0Modules, 26, 0);
@@ -873,8 +882,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
if(CONFIG(PATCHGAMES)) if(CONFIG(PATCHGAMES))
{ {
if(!loadTitleCodeSection(progId, code, size) || if(!applyCodeIpsPatch(progId, code, size)) goto error;
!applyCodeIpsPatch(progId, code, size)) goto error;
if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000) if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
{ {
@@ -894,5 +902,4 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
error: error:
svcBreak(USERBREAK_ASSERT); svcBreak(USERBREAK_ASSERT);
while(true);
} }

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include <3ds/types.h> #include <3ds/types.h>
#include "exheader.h"
#include "ifile.h"
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) #define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) #define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
@@ -12,12 +14,14 @@
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1) #define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
enum multiOptions enum multiOptions
{ {
DEFAULTEMU = 0, DEFAULTEMU = 0,
BRIGHTNESS, BRIGHTNESS,
SPLASH, SPLASH,
SPLASH_DURATION,
PIN, PIN,
NEWCPU NEWCPU
}; };
@@ -30,9 +34,14 @@ enum singleOptions
PATCHGAMES, PATCHGAMES,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHACCESS,
PATCHUNITINFO, PATCHUNITINFO,
DISABLEARM11EXCHANDLERS DISABLEARM11EXCHANDLERS
}; };
extern u32 config, multiConfig, bootConfig;
extern bool isN3DS, isSafeMode, isSdMode;
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress); void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress);
Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags);
bool loadTitleCodeSection(u64 progId, u8 *code, u32 size);
bool loadTitleExheader(u64 progId, exheader_header *exheader);

21
sysmodules/pxi/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 TuxSH
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.

47
sysmodules/pxi/Makefile Normal file
View File

@@ -0,0 +1,47 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
name := pxi
dir_source := source
dir_build := build
dir_out := ../../$(dir_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 -g -ffast-math -mword-relocations \
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
LDFLAGS := -specs=3dsx.specs -Wl,--gc-sections $(ARCH)
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.c))
.PHONY: all
all: $(dir_out)/$(name).cxi
.PHONY: clean
clean:
@rm -rf $(dir_build)
$(dir_out)/$(name).cxi: $(dir_build)/$(name).elf
@makerom -f ncch -rsf $(name).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)

15
sysmodules/pxi/README.md Normal file
View File

@@ -0,0 +1,15 @@
# 3ds_pxi
Open source replacement of the ARM11 PXI system module.
This is licensed under the MIT license.
# Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
# Credits
This list is not complete at all:
* @Subv, for the process patch that used to be used in Luma3DS which I modified to assist me in PXI sysmodule reverse-engineering
* @yifanlu, for the work his own work on loader
* @Mrrraou, for intensive testing back in June/July 2016
* @jackron, for makerom support and help
* Many #Cakey and #3dsdev folks I haven't mentioned here, etc.

123
sysmodules/pxi/pxi.rsf Normal file
View File

@@ -0,0 +1,123 @@
BasicInfo:
Title : pxi
CompanyCode : "00"
ProductCode : lennybuilder
ContentType : Application
Logo : None
TitleInfo:
UniqueId : 0x14
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 : 13
DisableDebug : false
EnableForceDebug : false
CanWriteSharedPage : false
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : false
PermitMainFunctionArgument : false
CanShareDeviceMemory : false
RunnableOnSleep : true
SpecialMemoryArrange : false
ResourceLimitCategory : Other
CoreVersion : 2
DescVersion : 2
MemoryType : Base # Application / System / Base
HandleTableSize: 0
IORegisterMapping:
- 1ec63000
SystemCallAccess:
AcceptSession: 74
ArbitrateAddress: 34
Break: 60
BindInterrupt: 80
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreatePort: 71
CreateSemaphore: 21
CreateSessionToPort: 72
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
FlushProcessDataCache: 84
GetCurrentProcessorNumber: 17
GetDmaState: 87
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
InvalidateProcessDataCache: 82
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
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
StartInterProcessDma: 85
StopDma: 86
StoreProcessDataCache: 83
UnmapMemoryBlock: 32
UnbindInterrupt: 81
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
- 0x50
- 0x51
- 0x52
- 0x53
ServiceAccessControl:
FileSystemAccess:
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 0
StackSize: 0x1000

View File

@@ -0,0 +1,42 @@
/*
MyThread.c:
Small threading library, based off ctrulib.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "MyThread.h"
#include "memory.h"
static void _thread_begin(void* arg)
{
MyThread *t = (MyThread *)arg;
t->ep();
MyThread_Exit();
}
Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity)
{
t->ep = entrypoint;
t->stacktop = (u8 *)stack + stackSize;
return svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, affinity);
}
Result MyThread_Join(MyThread *thread, s64 timeout_ns)
{
if (thread == NULL) return 0;
Result res = svcWaitSynchronization(thread->handle, timeout_ns);
if(R_FAILED(res)) return res;
svcCloseHandle(thread->handle);
thread->handle = (Handle)0;
return res;
}
void MyThread_Exit(void)
{
svcExitThread();
}

View File

@@ -0,0 +1,28 @@
/*
MyThread.h:
Small threading library, based off ctrulib.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include <3ds/types.h>
#include <3ds/result.h>
#include <3ds/svc.h>
#include <3ds/synchronization.h>
#define THREAD_STACK_SIZE 0x1000
typedef struct MyThread
{
Handle handle;
void (*ep)(void);
bool finished;
void* stacktop;
} MyThread;
Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity);
Result MyThread_Join(MyThread *thread, s64 timeout_ns);
void MyThread_Exit(void);

139
sysmodules/pxi/source/PXI.c Normal file
View File

@@ -0,0 +1,139 @@
/*
PXI.c:
PXI I/O functions.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "PXI.h"
void PXIReset(void)
{
REG_PXI_SYNC = 0;
REG_PXI_CNT = CNT_CLEAR_SEND_FIFO;
for(u32 i = 0; i < 16; i += 2)
{
REG_PXI_RECV;
REG_PXI_RECV;
}
REG_PXI_CNT = 0;
REG_PXI_CNT = CNT_ENABLE_FIFOs | CNT_ACKNOWLEDGE_FIFO_ERROR | CNT_CLEAR_SEND_FIFO;
}
void PXITriggerSync9IRQ(void)
{
REG_PXI_INTERRUPT_CNT |= SYNC_TRIGGER_SYNC9_IRQ;
}
bool PXIIsSendFIFOFull(void)
{
return (REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS) != 0;
}
void PXISendByte(u8 byte)
{
REG_PXI_BYTE_SENT_TO_REMOTE = byte;
}
void PXISendWord(u32 word)
{
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
REG_PXI_SEND = word;
}
void PXISendBuffer(const u32 *buffer, u32 nbWords)
{
for(; nbWords > 0; nbWords--)
{
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
REG_PXI_SEND = *buffer++;
}
}
bool PXIIsReceiveFIFOEmpty(void)
{
return (REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS) != 0;
}
u8 PXIReceiveByte(void)
{
return REG_PXI_BYTE_RECEIVED_FROM_REMOTE;
}
u32 PXIReceiveWord(void)
{
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
return REG_PXI_RECV;
}
void PXIReceiveBuffer(u32 *buffer, u32 nbWords)
{
for(; nbWords > 0; nbWords--)
{
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
*buffer++ = REG_PXI_RECV;
}
}
Result bindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
{
Result res = 0;
u32 mask = CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
if(receiveFIFONotEmptyInterrupt != NULL)
{
res = svcBindInterrupt(0x53, *receiveFIFONotEmptyInterrupt, 0, false);
if(R_FAILED(res))
{
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
return res;
}
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
}
if(sendFIFOEmptyInterrupt != NULL)
{
res = svcBindInterrupt(0x52, *sendFIFOEmptyInterrupt, 0, false);
if(R_FAILED(res))
{
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
return res;
}
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
}
if(syncInterrupt != NULL)
{
res = svcBindInterrupt(0x50, *syncInterrupt, 0, false);
if(R_FAILED(res))
{
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
return res;
}
REG_PXI_INTERRUPT_CNT |= SYNC_ENABLE_SYNC11_IRQ;
}
return res;
}
void unbindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
{
if(receiveFIFONotEmptyInterrupt != NULL)
{
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
svcUnbindInterrupt(0x53, *receiveFIFONotEmptyInterrupt);
}
if(sendFIFOEmptyInterrupt != NULL)
{
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
svcUnbindInterrupt(0x52, *sendFIFOEmptyInterrupt);
}
if(syncInterrupt != NULL)
{
REG_PXI_INTERRUPT_CNT &= ~SYNC_ENABLE_SYNC11_IRQ;
svcUnbindInterrupt(0x50, *syncInterrupt);
}
}

View File

@@ -0,0 +1,47 @@
/*
PXI.h:
PXI I/O functions.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include <3ds.h>
#define PXI_REGS_BASE 0x1EC63000
#define REG_PXI_SYNC *(vu32 *)(PXI_REGS_BASE + 0)
#define REG_PXI_BYTE_RECEIVED_FROM_REMOTE *(vu8 *)(PXI_REGS_BASE)
#define REG_PXI_BYTE_SENT_TO_REMOTE *(vu8 *)(PXI_REGS_BASE + 1)
#define REG_PXI_INTERRUPT_CNT *(vu8 *)(PXI_REGS_BASE + 3)
#define SYNC_TRIGGER_SYNC9_IRQ (1U << 6)
#define SYNC_ENABLE_SYNC11_IRQ (1U << 7)
#define REG_PXI_CNT *(vu16 *)(PXI_REGS_BASE + 4)
#define CNT_SEND_FIFO_FULL_STATUS (1U << 1)
#define CNT_ENABLE_SEND_FIFO_EMPTY_IRQ (1U << 2)
#define CNT_CLEAR_SEND_FIFO (1U << 3)
#define CNT_RECEIVE_FIFO_EMPTY_STATUS (1U << 8)
#define CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ (1U << 10)
#define CNT_ACKNOWLEDGE_FIFO_ERROR (1U << 14)
#define CNT_ENABLE_FIFOs (1U << 15)
#define REG_PXI_SEND *(vu32 *)(PXI_REGS_BASE + 8)
#define REG_PXI_RECV *(vu32 *)(PXI_REGS_BASE + 12)
void PXIReset(void);
void PXITriggerSync9IRQ(void);
bool PXIIsSendFIFOFull(void);
void PXISendByte(u8 byte);
void PXISendWord(u32 word);
void PXISendBuffer(const u32 *buffer, u32 nbWords);
bool PXIIsReceiveFIFOEmpty(void);
u8 PXIReceiveByte(void);
u32 PXIReceiveWord(void);
void PXIReceiveBuffer(u32 *buffer, u32 nbWords);
Result bindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt);
void unbindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt);

View File

@@ -0,0 +1,94 @@
/*
common.h:
Common types and global variables.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include <3ds.h>
typedef enum SessionState
{
STATE_IDLE = 0,
STATE_RECEIVED_FROM_ARM11 = 1,
STATE_SENT_TO_ARM9 = 2,
STATE_RECEIVED_FROM_ARM9 = 3
} SessionState;
typedef struct SessionData
{
SessionState state;
u32 buffer[0x100/4];
Handle handle;
u32 usedStaticBuffers;
RecursiveLock lock;
} SessionData;
#define NB_STATIC_BUFFERS 21
typedef struct SessionManager
{
Handle sendAllBuffersToArm9Event, replySemaphore, PXISRV11CommandReceivedEvent, PXISRV11ReplySentEvent;
u32 latest_PXI_MC5_val, pendingArm9Commands;
u32 receivedServiceId;
RecursiveLock senderLock;
bool sendingDisabled;
SessionData sessionData[10];
u32 currentlyProvidedStaticBuffers, freeStaticBuffers;
} SessionManager;
//Page alignment is mandatory there
extern u32 ALIGN(0x1000) staticBuffers[NB_STATIC_BUFFERS][0x1000/4];
extern Handle PXISyncInterrupt, PXITransferMutex;
extern Handle terminationRequestedEvent;
extern bool shouldTerminate;
extern SessionManager sessionManager;
extern const u32 nbStaticBuffersByService[10];
static inline Result assertSuccess(Result res)
{
if(R_FAILED(res)) svcBreak(USERBREAK_PANIC);
return res;
}
static inline s32 getMSBPosition(u32 val)
{
return 31 - (s32) __builtin_clz(val);
}
static inline s32 getLSBPosition(u32 val)
{
return __builtin_ffs(val) - 1;
}
static inline u32 clearMSBs(u32 val, u32 nb)
{
for(u32 i = 0; i < nb; i++)
{
s32 pos = getMSBPosition(val);
if(pos == -1) break;
val &= ~(1 << pos);
}
return val;
}
static inline u32 countNbBitsSet(u32 val)
{
u32 nb = 0;
while(val != 0)
{
val = clearMSBs(val, 1);
nb++;
}
return nb;
}

View File

@@ -0,0 +1,211 @@
/*
main.c
(De)initialization stuff. It's also here where sessions are being accepted.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "PXI.h"
#include "common.h"
#include "MyThread.h"
#include "receiver.h"
#include "sender.h"
#include "memory.h"
Handle PXISyncInterrupt = 0, PXITransferMutex = 0;
Handle terminationRequestedEvent = 0;
bool shouldTerminate = false;
SessionManager sessionManager = {0};
const char *serviceNames[10] =
{
"pxi:mc",
"PxiFS0",
"PxiFS1",
"PxiFSB",
"PxiFSR",
"PxiPM",
"pxi:dev", //in the official PXI module maxSessions(pxi:dev) == 2. It doesn't matter anyways, since srvSysRegisterService is always called with 1
"pxi:am9",
"pxi:ps9",
"pxi:srv11",
};
const u32 nbStaticBuffersByService[10] = {0, 2, 2, 2, 2, 1, 4, 4, 4, 0};
u32 ALIGN(0x1000) staticBuffers[NB_STATIC_BUFFERS][0x400] = {{0}};
static inline void initPXI(void)
{
Result res;
Handle handles[2] = {0};
PXIReset();
if(PXISyncInterrupt != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
assertSuccess(svcCreateEvent(&PXISyncInterrupt, RESET_ONESHOT));
if(PXITransferMutex != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
assertSuccess(svcCreateMutex(&PXITransferMutex, false));
assertSuccess(svcCreateEvent(&handles[0], RESET_ONESHOT)); //receive FIFO not empty
assertSuccess(svcCreateEvent(&handles[1], RESET_ONESHOT)); //send FIFO empty
assertSuccess(bindPXIInterrupts(&PXISyncInterrupt, &handles[0], &handles[1]));
s32 handleIndex;
do
{
while(!PXIIsSendFIFOFull()) PXISendWord(0);
res = assertSuccess(svcWaitSynchronization(handles[0], 0LL));
if(R_DESCRIPTION(res) == RD_TIMEOUT)
assertSuccess(svcWaitSynchronizationN(&handleIndex, handles, 2, false, -1LL));
else
handleIndex = 0;
} while(handleIndex != 0);
unbindPXIInterrupts(NULL, &handles[0], &handles[1]);
PXISendByte(1);
while(PXIReceiveByte() < 1);
while (!PXIIsReceiveFIFOEmpty())
PXIReceiveWord();
PXISendByte(2);
while(PXIReceiveByte() < 2);
svcCloseHandle(handles[0]);
svcCloseHandle(handles[1]);
}
static inline void exitPXI(void)
{
unbindPXIInterrupts(&PXISyncInterrupt, NULL, NULL);
svcCloseHandle(PXITransferMutex);
svcCloseHandle(PXISyncInterrupt);
PXIReset();
}
static u8 ALIGN(8) receiverStack[THREAD_STACK_SIZE];
static u8 ALIGN(8) senderStack[THREAD_STACK_SIZE];
static u8 ALIGN(8) PXISRV11HandlerStack[THREAD_STACK_SIZE];
// this is called before main
void __appInit()
{
assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY));
assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT));
assertSuccess(svcCreateSemaphore(&sessionManager.replySemaphore, 0, 9));
assertSuccess(svcCreateEvent(&sessionManager.PXISRV11CommandReceivedEvent, RESET_ONESHOT));
assertSuccess(svcCreateEvent(&sessionManager.PXISRV11ReplySentEvent, RESET_ONESHOT));
initPXI();
for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{
res = srvInit();
if(R_FAILED(res) && res != (Result)0xD88007FA)
svcBreak(USERBREAK_PANIC);
}
}
// this is called after main exits
void __appExit()
{
srvExit();
exitPXI();
svcCloseHandle(terminationRequestedEvent);
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
svcCloseHandle(sessionManager.replySemaphore);
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
}
// stubs for non-needed pre-main functions
void __system_initSyscalls(){}
Result __sync_init(void);
Result __sync_fini(void);
void __ctru_exit()
{
__appExit();
__sync_fini();
svcExitProcess();
}
void initSystem()
{
__sync_init();
__system_initSyscalls();
__appInit();
}
int main(void)
{
Handle handles[10] = {0}; //notification handle + service handles
MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
for(u32 i = 0; i < 9; i++)
assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1));
assertSuccess(MyThread_Create(&receiverThread, receiver, receiverStack, THREAD_STACK_SIZE, 0x2D, -2));
assertSuccess(MyThread_Create(&senderThread, sender, senderStack, THREAD_STACK_SIZE, 0x2D, -2));
assertSuccess(MyThread_Create(&PXISRV11HandlerThread, PXISRV11Handler, PXISRV11HandlerStack, THREAD_STACK_SIZE, 0x2D, -2));
assertSuccess(srvEnableNotification(&handles[0]));
while(!shouldTerminate)
{
s32 index = 0;
assertSuccess(svcWaitSynchronizationN(&index, handles, 10, false, -1LL));
if(index == 0)
{
u32 notificationId;
assertSuccess(srvReceiveNotification(&notificationId));
if(notificationId == 0x100) shouldTerminate = true;
}
else
{
Handle session = 0;
SessionData *data = &sessionManager.sessionData[index - 1];
assertSuccess(svcAcceptSession(&session, handles[index]));
RecursiveLock_Lock(&sessionManager.senderLock);
if(data->handle != 0)
svcBreak(USERBREAK_PANIC);
data->handle = session;
assertSuccess(svcSignalEvent(sessionManager.sendAllBuffersToArm9Event));
RecursiveLock_Unlock(&sessionManager.senderLock);
}
}
u32 PXIMC_OnPXITerminate = 0x10000; //TODO: see if this is correct
sessionManager.sessionData[0].state = STATE_SENT_TO_ARM9;
sendPXICmdbuf(NULL, 0, &PXIMC_OnPXITerminate);
assertSuccess(MyThread_Join(&receiverThread, -1LL));
assertSuccess(MyThread_Join(&senderThread, -1LL));
assertSuccess(MyThread_Join(&PXISRV11HandlerThread, -1LL));
for(u32 i = 0; i < 10; i++)
svcCloseHandle(handles[i]);
return 0;
}

View File

@@ -0,0 +1,19 @@
/*
memory.c:
Memory functions
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "memory.h"
//Adpated from CakesFW
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];
}

View File

@@ -0,0 +1,13 @@
/*
memory.h:
Memory functions
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include <3ds/types.h>
void memcpy(void *dest, const void *src, u32 size);

View File

@@ -0,0 +1,69 @@
/*
receiver.c:
Fetches replies coming from Process9, writing them in the appropriate buffer.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "receiver.h"
#include "PXI.h"
#include "memory.h"
static inline void receiveFromArm9(void)
{
u32 serviceId = PXIReceiveWord();
//The offcical implementation can return 0xD90043FA
if(((serviceId >= 10)) || (sessionManager.sessionData[serviceId].state != STATE_SENT_TO_ARM9))
svcBreak(USERBREAK_PANIC);
sessionManager.receivedServiceId = serviceId;
RecursiveLock_Lock(&sessionManager.sessionData[serviceId].lock);
u32 replyHeader = PXIReceiveWord();
u32 replySizeWords = (replyHeader & 0x3F) + ((replyHeader & 0xFC0) >> 6) + 1;
if(replySizeWords > 0x40) svcBreak(USERBREAK_PANIC);
u32 *buf = sessionManager.sessionData[serviceId].buffer;
buf[0] = replyHeader;
PXIReceiveBuffer(buf + 1, replySizeWords - 1);
sessionManager.sessionData[serviceId].state = STATE_RECEIVED_FROM_ARM9;
RecursiveLock_Unlock(&sessionManager.sessionData[serviceId].lock);
if(serviceId == 0 && shouldTerminate)
{
assertSuccess(svcSignalEvent(terminationRequestedEvent));
return;
}
if(serviceId != 9)
{
s32 count;
assertSuccess(svcReleaseSemaphore(&count, sessionManager.replySemaphore, 1));
}
else
{
assertSuccess(svcSignalEvent(sessionManager.PXISRV11CommandReceivedEvent));
assertSuccess(svcWaitSynchronization(sessionManager.PXISRV11ReplySentEvent, -1LL));
if( (sessionManager.sessionData[serviceId].state != STATE_SENT_TO_ARM9))
svcBreak(USERBREAK_PANIC);
}
}
void receiver(void)
{
Handle handles[] = {PXISyncInterrupt, terminationRequestedEvent};
assertSuccess(svcWaitSynchronization(sessionManager.PXISRV11ReplySentEvent, -1LL));
while(true)
{
s32 index;
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
if(index == 1) return;
while(!PXIIsReceiveFIFOEmpty())
receiveFromArm9();
}
}

View File

@@ -0,0 +1,13 @@
/*
receiver.h:
Fetches replies coming from Process9, writing them in the appropriate buffer.
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include "common.h"
void receiver(void);

View File

@@ -0,0 +1,300 @@
/*
sender.c
Handles commands from arm11 processes, then sends them to Process9, and replies to arm11 processes the replies received from Process9 (=> receiver.c).
(except for PXISRV11)
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#include "sender.h"
#include "PXI.h"
#include "memory.h"
Result sendPXICmdbuf(Handle *additionalHandle, u32 serviceId, u32 *buffer)
{
Result res = 0;
if(additionalHandle != NULL)
{
s32 index = 1;
bool cancelled = false;
Handle handles[2] = {PXITransferMutex, *additionalHandle};
res = assertSuccess(svcWaitSynchronization(PXITransferMutex, 0LL));
if(R_DESCRIPTION(res) == RD_TIMEOUT)
{
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
cancelled = index == 1;
}
else
cancelled = false;
if(cancelled)
return 0xD92043FB; // cancel requested
}
else
assertSuccess(svcWaitSynchronization(PXITransferMutex, -1LL));
PXISendWord(serviceId & 0xFF);
PXITriggerSync9IRQ(); //notify arm9
PXISendBuffer(buffer, (buffer[0] & 0x3F) + ((buffer[0] & 0xFC0) >> 6) + 1);
svcReleaseMutex(PXITransferMutex);
return 0;
}
static void updateTLSForStaticBuffers(void)
{
u32 *staticBufs = getThreadStaticBuffers();
u32 val = sessionManager.currentlyProvidedStaticBuffers;
for(u32 i = 0; i < 4; i++)
{
s32 pos = getLSBPosition(val);
if(pos != -1)
{
staticBufs[2 * i] = IPC_Desc_StaticBuffer(0x1000, 0);
staticBufs[2 * i + 1] = (u32)&staticBuffers[pos];
val &= ~(1 << pos);
}
else
{
staticBufs[2 * i] = IPC_Desc_StaticBuffer(0, 0);
staticBufs[2 * i + 1] = 0;
}
}
}
static void acquireStaticBuffers(void)
{
u32 freeStaticBuffersOrig = sessionManager.freeStaticBuffers;
sessionManager.freeStaticBuffers = clearMSBs(sessionManager.freeStaticBuffers, 4);
sessionManager.currentlyProvidedStaticBuffers = ~sessionManager.freeStaticBuffers & freeStaticBuffersOrig;
updateTLSForStaticBuffers();
}
static void releaseStaticBuffers(u32 *src, u32 nb)
{
u32 val = clearMSBs(*src, nb);
sessionManager.freeStaticBuffers |= ~val & *src;
*src = val;
}
void sender(void)
{
Handle handles[12] = {terminationRequestedEvent, sessionManager.sendAllBuffersToArm9Event, sessionManager.replySemaphore};
Handle replyTarget = 0;
Result res = 0;
s32 index;
u32 *cmdbuf = getThreadCommandBuffer();
u32 nbIdleSessions = 0;
u32 posToServiceId[9] = {0};
RecursiveLock_Lock(&sessionManager.senderLock);
//Setting static buffers is needed for IPC translation types 2 and 3 (otherwise ReplyAndReceive will dereference NULL)
sessionManager.freeStaticBuffers = (1 << NB_STATIC_BUFFERS) - 1;
acquireStaticBuffers();
do
{
if(replyTarget == 0) //send to arm9
{
for(u32 i = 0; i < 9; i++)
{
SessionData *data = &sessionManager.sessionData[i];
if(data->handle == 0 || data->state != STATE_RECEIVED_FROM_ARM11)
continue;
if(sessionManager.sendingDisabled)
{
if (sessionManager.pendingArm9Commands != 0 || sessionManager.latest_PXI_MC5_val == 0)
continue;
}
else
sessionManager.pendingArm9Commands++;
RecursiveLock_Lock(&data->lock);
data->state = STATE_SENT_TO_ARM9;
res = sendPXICmdbuf(&terminationRequestedEvent, i, data->buffer);
RecursiveLock_Unlock(&data->lock);
if(R_FAILED(res))
goto terminate;
}
cmdbuf[0] = 0xFFFF0000; //Kernel11
}
nbIdleSessions = 0;
for(u32 i = 0; i < 9; i++)
{
if(sessionManager.sessionData[i].handle != 0 && sessionManager.sessionData[i].state == STATE_IDLE)
{
handles[3 + nbIdleSessions] = sessionManager.sessionData[i].handle;
posToServiceId[nbIdleSessions++] = i;
}
}
RecursiveLock_Unlock(&sessionManager.senderLock);
res = svcReplyAndReceive(&index, handles, 3 + nbIdleSessions, replyTarget);
RecursiveLock_Lock(&sessionManager.senderLock);
if((u32)res == 0xC920181A) //session closed by remote
{
u32 i;
if(index == -1)
for(i = 0; i < 9 && replyTarget != sessionManager.sessionData[i].handle; i++);
else
i = posToServiceId[index - 3];
if(i >= 9) svcBreak(USERBREAK_PANIC);
svcCloseHandle(sessionManager.sessionData[i].handle);
sessionManager.sessionData[i].handle = replyTarget = 0;
continue;
}
else if(R_FAILED(res) || (u32)index >= 3 + nbIdleSessions)
svcBreak(USERBREAK_PANIC);
switch(index)
{
case 0: //terminaton requested
break;
case 1:
replyTarget = 0;
continue;
case 2: //arm9 reply
{
u32 sessionId = 0;
for(sessionId = 0; sessionId < 9 && sessionManager.sessionData[sessionId].state != STATE_RECEIVED_FROM_ARM9; sessionId++);
if(sessionId == 9) svcBreak(USERBREAK_PANIC);
SessionData *data = &sessionManager.sessionData[sessionId];
RecursiveLock_Lock(&data->lock);
if(data->state != STATE_RECEIVED_FROM_ARM9) svcBreak(USERBREAK_PANIC);
if(sessionManager.latest_PXI_MC5_val == 2)
{
if(sessionManager.pendingArm9Commands != 0) svcBreak(USERBREAK_PANIC);
sessionManager.sendingDisabled = false;
}
else if(sessionManager.latest_PXI_MC5_val == 0)
(sessionManager.pendingArm9Commands)--;
u32 bufSize = 4 * ((data->buffer[0] & 0x3F) + ((data->buffer[0] & 0xFC0) >> 6) + 1);
if(bufSize > 0x100) svcBreak(USERBREAK_PANIC);
memcpy(cmdbuf, data->buffer, bufSize);
releaseStaticBuffers(&data->usedStaticBuffers, 4);
data->state = STATE_IDLE;
replyTarget = data->handle;
RecursiveLock_Unlock(&data->lock);
break;
}
default: //arm11 command received
{
u32 serviceId = posToServiceId[index - 3];
SessionData *data = &sessionManager.sessionData[serviceId];
RecursiveLock_Lock(&data->lock);
if(data->state != STATE_IDLE) svcBreak(USERBREAK_PANIC);
if(!(serviceId == 0 && (cmdbuf[0] >> 16) == 5)) //if not pxi:mc 5
sessionManager.latest_PXI_MC5_val = 0;
else if((u8)(cmdbuf[1]) != 0)
{
sessionManager.latest_PXI_MC5_val = 1;
if(sessionManager.sendingDisabled) svcBreak(USERBREAK_PANIC);
sessionManager.sendingDisabled = true;
}
else
{
sessionManager.latest_PXI_MC5_val = 2;
if(!sessionManager.sendingDisabled) svcBreak(USERBREAK_PANIC);
}
u32 bufSize = 4 * ((cmdbuf[0] & 0x3F) + ((cmdbuf[0] & 0xFC0) >> 6) + 1);
if(bufSize > 0x100) svcBreak(USERBREAK_PANIC);
memcpy(data->buffer, cmdbuf, bufSize);
data->state = STATE_RECEIVED_FROM_ARM11;
replyTarget = 0;
releaseStaticBuffers(&sessionManager.currentlyProvidedStaticBuffers, 4 - nbStaticBuffersByService[serviceId]);
data->usedStaticBuffers = sessionManager.currentlyProvidedStaticBuffers;
acquireStaticBuffers();
RecursiveLock_Unlock(&data->lock);
break;
}
}
}
while(index != 0);
terminate:
for(u32 i = 0; i < 9; i++)
{
if(sessionManager.sessionData[i].handle != 0)
svcCloseHandle(sessionManager.sessionData[i].handle);
}
RecursiveLock_Unlock(&sessionManager.senderLock);
}
void PXISRV11Handler(void)
{
// Assumption: only 1 request is sent to this service at a time
Handle handles[] = {sessionManager.PXISRV11CommandReceivedEvent, terminationRequestedEvent};
SessionData *data = &sessionManager.sessionData[9];
data->state = STATE_SENT_TO_ARM9;
assertSuccess(svcSignalEvent(sessionManager.PXISRV11ReplySentEvent));
while(true)
{
s32 index;
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
if(index == 1) return;
else
{
RecursiveLock_Lock(&data->lock);
if(data->state != STATE_RECEIVED_FROM_ARM9)
svcBreak(USERBREAK_PANIC);
data->state = STATE_IDLE;
if(data->buffer[0] >> 16 != 1)
{
data->buffer[0] = 0x40;
data->buffer[1] = 0xD900182F; //unimplemented/invalid command
}
else
{
data->buffer[0] = 0x10040;
data->buffer[1] = srvPublishToSubscriber(data->buffer[1], 1);
data->state = STATE_RECEIVED_FROM_ARM11;
if(data->buffer[1] == 0xD8606408)
svcBreak(USERBREAK_PANIC);
}
assertSuccess(sendPXICmdbuf(&terminationRequestedEvent, 9, data->buffer));
data->state = STATE_SENT_TO_ARM9;
assertSuccess(svcSignalEvent(sessionManager.PXISRV11ReplySentEvent));
RecursiveLock_Unlock(&data->lock);
}
}
}

View File

@@ -0,0 +1,15 @@
/*
sender.h
Handles commands from arm11 processes, then sends them to Process9, and replies to arm11 processes the replies received from Process9 (=> receiver.c) (except for PXISRV11).
(c) TuxSH, 2016-2017
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
*/
#pragma once
#include "common.h"
Result sendPXICmdbuf(Handle *additionalHandle, u32 serviceId, u32 *buffer);
void sender(void);
void PXISRV11Handler(void);

View File

@@ -6,11 +6,6 @@ endif
include $(DEVKITARM)/3ds_rules 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)) name := $(shell basename $(CURDIR))
dir_source := source dir_source := source
@@ -26,7 +21,7 @@ INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ARCH := -mcpu=mpcore -mfloat-abi=hard ARCH := -mcpu=mpcore -mfloat-abi=hard
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -mtp=soft -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \ CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -mtp=soft -fno-builtin -std=c11 -O2 -ffast-math -mword-relocations \
-fomit-frame-pointer -ffunction-sections -fdata-sections $(INCLUDE) -I$(dir_include) -DARM11 -D_3DS -fomit-frame-pointer -ffunction-sections -fdata-sections $(INCLUDE) -I$(dir_include) -DARM11 -D_3DS
LDFLAGS := -specs=3dsx.specs -g $(ARCH) -mtp=soft -Wl,--section-start,.text=0x14000000 -Wl,--gc-sections LDFLAGS := -specs=3dsx.specs -g $(ARCH) -mtp=soft -Wl,--section-start,.text=0x14000000 -Wl,--gc-sections

View File

@@ -63,6 +63,7 @@
#define COLOR_TITLE RGB565(0x00, 0x26, 0x1F) #define COLOR_TITLE RGB565(0x00, 0x26, 0x1F)
#define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F) #define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F)
#define COLOR_RED RGB565(0x1F, 0x00, 0x00) #define COLOR_RED RGB565(0x1F, 0x00, 0x00)
#define COLOR_GREEN RGB565(0x00, 0x1F, 0x00)
#define COLOR_BLACK RGB565(0x00, 0x00, 0x00) #define COLOR_BLACK RGB565(0x00, 0x00, 0x00)
#define DRAW_MAX_FORMATTED_STRING_SIZE 512 #define DRAW_MAX_FORMATTED_STRING_SIZE 512

View File

@@ -111,7 +111,7 @@ typedef struct GDBContext
u32 nbWatchpoints; u32 nbWatchpoints;
u32 watchpoints[2]; u32 watchpoints[2];
bool isGDB; bool enableExternalMemoryAccess;
char *commandData, *commandEnd; char *commandData, *commandEnd;
int latestSentPacketSize; int latestSentPacketSize;
char buffer[GDB_BUF_LEN + 4]; char buffer[GDB_BUF_LEN + 4];

View File

@@ -34,6 +34,8 @@
GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo); GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle); GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig); GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches); GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess);
GDB_DECLARE_QUERY_HANDLER(Rcmd); GDB_DECLARE_QUERY_HANDLER(Rcmd);

View File

@@ -35,3 +35,6 @@ extern Menu rosalinaMenu;
void RosalinaMenu_TakeScreenshot(void); void RosalinaMenu_TakeScreenshot(void);
void RosalinaMenu_ShowCredits(void); void RosalinaMenu_ShowCredits(void);
void RosalinaMenu_ProcessList(void); void RosalinaMenu_ProcessList(void);
void RosalinaMenu_PowerOff(void);
void RosalinaMenu_Reboot(void);
void RosalinaMenu_Cheats(void);

View File

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

View File

@@ -35,5 +35,3 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
void MiscellaneousMenu_ChangeMenuCombo(void); void MiscellaneousMenu_ChangeMenuCombo(void);
void MiscellaneousMenu_SaveSettings(void); void MiscellaneousMenu_SaveSettings(void);
void MiscellaneousMenu_InputRedirection(void); void MiscellaneousMenu_InputRedirection(void);
void MiscellaneousMenu_PowerOff(void);
void MiscellaneousMenu_Reboot(void);

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