├── startenv.bat ├── .gitignore ├── release ├── BootNTR.cia └── BootNTR-Mode3.cia ├── resources ├── icon.png ├── banner.bin ├── AppInfo-0 ├── AppInfo └── AppInfo-3 ├── lib └── ctrcommon │ ├── .gitignore │ ├── tools │ ├── makerom-mac │ ├── makerom.exe │ ├── bannertool-mac │ ├── bannertool.exe │ ├── makerom-linux │ ├── bannertool-linux │ ├── template-cia.rsf │ ├── template-3ds.rsf │ └── make_base │ ├── data │ ├── ctrcommon_font.bin │ └── ctrcommon_shader.vsh │ ├── include │ ├── ctrcommon_font_bin.h │ ├── ctrcommon_shader_vsh_shbin.h │ └── ctrcommon │ │ ├── ir.hpp │ │ ├── nor.hpp │ │ ├── types.hpp │ │ ├── socket.hpp │ │ ├── sound.hpp │ │ ├── fs.hpp │ │ ├── input.hpp │ │ ├── ui.hpp │ │ ├── app.hpp │ │ ├── platform.hpp │ │ └── gpu.hpp │ ├── source │ └── ctrcommon │ │ ├── service.hpp │ │ ├── ir.cpp │ │ ├── nor.cpp │ │ ├── fs.cpp │ │ ├── sound.cpp │ │ ├── input.cpp │ │ ├── socket.cpp │ │ ├── service.cpp │ │ ├── app.cpp │ │ ├── gput.cpp │ │ ├── platform.cpp │ │ └── ui.cpp │ ├── README.md │ ├── LICENSE.txt │ └── Makefile ├── tools ├── process_homemenu.bat ├── locate_offsets.py └── locate_homemenu.py ├── README.md ├── source ├── ntr_config.h ├── misc.s ├── ns.h ├── mysvcs.h └── svc.s ├── LICENSE ├── template-cia.rsf ├── template-cia-0.rsf ├── template-cia-3.rsf └── Makefile /startenv.bat: -------------------------------------------------------------------------------- 1 | set PATH=%PATH%;C:\devkitPro\devkitARM\bin 2 | cmd -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | CMakeLists.txt 3 | 4 | build 5 | 6 | ctrcommon.tar.bz2 7 | 8 | output 9 | -------------------------------------------------------------------------------- /release/BootNTR.cia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/release/BootNTR.cia -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/resources/icon.png -------------------------------------------------------------------------------- /lib/ctrcommon/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | CMakeLists.txt 3 | 4 | build 5 | lib 6 | 7 | ctrcommon.tar.bz2 8 | -------------------------------------------------------------------------------- /resources/banner.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/resources/banner.bin -------------------------------------------------------------------------------- /tools/process_homemenu.bat: -------------------------------------------------------------------------------- 1 | del result.txt 2 | locate_homemenu.py pidf.dmp > result.txt 3 | 4 | pause -------------------------------------------------------------------------------- /release/BootNTR-Mode3.cia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/release/BootNTR-Mode3.cia -------------------------------------------------------------------------------- /lib/ctrcommon/tools/makerom-mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/makerom-mac -------------------------------------------------------------------------------- /lib/ctrcommon/tools/makerom.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/makerom.exe -------------------------------------------------------------------------------- /lib/ctrcommon/tools/bannertool-mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/bannertool-mac -------------------------------------------------------------------------------- /lib/ctrcommon/tools/bannertool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/bannertool.exe -------------------------------------------------------------------------------- /lib/ctrcommon/tools/makerom-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/makerom-linux -------------------------------------------------------------------------------- /lib/ctrcommon/data/ctrcommon_font.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/data/ctrcommon_font.bin -------------------------------------------------------------------------------- /lib/ctrcommon/tools/bannertool-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astronautlevel2/BootNTR/HEAD/lib/ctrcommon/tools/bannertool-linux -------------------------------------------------------------------------------- /resources/AppInfo-0: -------------------------------------------------------------------------------- 1 | APP_TITLE = BootNTR 2 | APP_DESCRIPTION = NTR CFW Loader. 3 | APP_AUTHOR = BootNTR 4 | APP_PRODUCT_CODE = CTR-P-BNTR 5 | APP_UNIQUE_ID = 0xb000 -------------------------------------------------------------------------------- /resources/AppInfo: -------------------------------------------------------------------------------- 1 | APP_TITLE = BootNTR 2 | APP_DESCRIPTION = NTR CFW Loader. 3 | APP_AUTHOR = BootNTR 4 | APP_PRODUCT_CODE = CTR-P-BNTR 5 | APP_UNIQUE_ID = 0xb000 -------------------------------------------------------------------------------- /resources/AppInfo-3: -------------------------------------------------------------------------------- 1 | APP_TITLE = BootNTR-Mode3 2 | APP_DESCRIPTION = NTR CFW Loader. 3 | APP_AUTHOR = BootNTR 4 | APP_PRODUCT_CODE = CTR-P-BNTU 5 | APP_UNIQUE_ID = 0xb003 -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon_font_bin.h: -------------------------------------------------------------------------------- 1 | extern const u8 ctrcommon_font_bin_end[]; 2 | extern const u8 ctrcommon_font_bin[]; 3 | extern const u32 ctrcommon_font_bin_size; 4 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon_shader_vsh_shbin.h: -------------------------------------------------------------------------------- 1 | extern const u8 ctrcommon_shader_vsh_shbin_end[]; 2 | extern const u8 ctrcommon_shader_vsh_shbin[]; 3 | extern const u32 ctrcommon_shader_vsh_shbin_size; 4 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/ir.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_IR_HPP__ 2 | #define __CTRCOMMON_IR_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | u32 irGetState(); 7 | void irSetState(u32 state); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/nor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_NOR_HPP__ 2 | #define __CTRCOMMON_NOR_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | bool norRead(u32 offset, void* data, u32 size); 7 | bool norWrite(u32 offset, void* data, u32 size); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/service.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_SERVICE_HPP__ 2 | #define __CTRCOMMON_SERVICE_HPP__ 3 | 4 | #include "ctrcommon/platform.hpp" 5 | #include "ctrcommon/types.hpp" 6 | 7 | #include 8 | 9 | void serviceCleanup(); 10 | bool serviceRequire(const std::string service); 11 | Error serviceParseError(u32 error); 12 | 13 | #endif -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_TYPES_HPP__ 2 | #define __CTRCOMMON_TYPES_HPP__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | typedef int8_t s8; 12 | typedef int16_t s16; 13 | typedef int32_t s32; 14 | typedef int64_t s64; 15 | 16 | #endif -------------------------------------------------------------------------------- /lib/ctrcommon/README.md: -------------------------------------------------------------------------------- 1 |
ctrcommon
2 | ========== 3 | 4 | Common utilities for use in 3DS homebrew. 5 | 6 | Requires [devkitARM](http://sourceforge.net/projects/devkitpro/files/devkitARM/), [aemstro](https://github.com/smealum/aemstro), and [ctrulib](https://github.com/smealum/ctrulib) to build. Run 'make' to build, and run 'make install' to install it to your devkitPro directory. 7 | -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/ir.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/ir.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include <3ds.h> 6 | 7 | u32 irGetState() { 8 | if(!serviceRequire("ir")) { 9 | return 0; 10 | } 11 | 12 | u32 state; 13 | IRU_GetIRLEDRecvState(&state); 14 | return state; 15 | } 16 | 17 | void irSetState(u32 state) { 18 | if(!serviceRequire("ir")) { 19 | return; 20 | } 21 | 22 | IRU_SetIRLEDState(state); 23 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BootNTR 2 | 3 | Boots NTR CFW. 4 | 5 | # Compatibility 6 | 7 | This is compatible with most firmwares between 9.2 and 11.2 firmware on USA, EUR, and JPN regions. 8 | 9 | # Future updates 10 | 11 | Add support for other regions 12 | 13 | If a future update breaks it, please open an issue stating your console, firmware version, and attach _all_ dumps on the SD card root. 14 | 15 | # Latest Build 16 | 17 | https://github.com/astronautlevel2/BootNTR/releases/download/3.3.1/BootNTR.cia 18 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/socket.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_SOCKET_HPP__ 2 | #define __CTRCOMMON_SOCKET_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | #include 7 | 8 | #include 9 | 10 | u64 htonll(u64 value); 11 | u64 ntohll(u64 value); 12 | u32 socketGetHostIP(); 13 | int socketListen(u16 port); 14 | FILE* socketAccept(int listeningSocket, std::string* acceptedIp = NULL); 15 | FILE* socketConnect(const std::string ipAddress, u16 port, int timeout = 10); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/sound.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_SOUND_HPP__ 2 | #define __CTRCOMMON_SOUND_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | #define SOUND_CHANNEL_COUNT 8 7 | 8 | typedef enum { 9 | SAMPLE_PCM8, 10 | SAMPLE_PCM16 11 | } SampleFormat; 12 | 13 | void* soundAlloc(u32 size); 14 | void soundFree(void* mem); 15 | bool soundPlay(u32 channel, void *samples, u32 numSamples, SampleFormat format, u32 sampleRate, float leftVolume, float rightVolume, bool loop); 16 | bool soundStop(u32 channel); 17 | bool soundFlush(); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/fs.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_FS_HPP__ 2 | #define __CTRCOMMON_FS_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | #include 7 | #include 8 | 9 | typedef enum { 10 | NAND, 11 | SD 12 | } MediaType; 13 | 14 | typedef struct { 15 | const std::string path; 16 | const std::string name; 17 | } FileInfo; 18 | 19 | u64 fsGetFreeSpace(MediaType mediaType); 20 | bool fsExists(const std::string path); 21 | bool fsIsDirectory(const std::string path); 22 | std::string fsGetExtension(const std::string path); 23 | bool fsHasExtension(const std::string path, const std::string extension); 24 | bool fsHasExtensions(const std::string path, const std::vector extensions); 25 | std::vector fsGetDirectoryContents(const std::string directory); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/nor.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/nor.hpp" 2 | #include "ctrcommon/platform.hpp" 3 | 4 | #include "service.hpp" 5 | 6 | #include <3ds.h> 7 | 8 | bool norRead(u32 offset, void* data, u32 size) { 9 | if(!serviceRequire("nor")) { 10 | return false; 11 | } 12 | 13 | Result result = CFGNOR_ReadData(offset, (u32*) data, size); 14 | if(result != 0) { 15 | platformSetError(serviceParseError((u32) result)); 16 | } 17 | 18 | return result == 0; 19 | } 20 | 21 | bool norWrite(u32 offset, void* data, u32 size) { 22 | if(!serviceRequire("nor")) { 23 | return false; 24 | } 25 | 26 | Result result = CFGNOR_WriteData(offset, (u32*) data, size); 27 | if(result != 0) { 28 | platformSetError(serviceParseError((u32) result)); 29 | } 30 | 31 | return result == 0; 32 | } -------------------------------------------------------------------------------- /source/ntr_config.h: -------------------------------------------------------------------------------- 1 | typedef struct _NTR_CONFIG { 2 | u32 bootNTRVersion; 3 | u32 isNew3DS; 4 | u32 firmVersion; 5 | 6 | u32 IoBasePad; 7 | u32 IoBaseLcd; 8 | u32 IoBasePdc; 9 | u32 PMSvcRunAddr; 10 | u32 PMPid; 11 | u32 HomeMenuPid; 12 | 13 | u32 HomeMenuVersion; 14 | u32 HomeMenuInjectAddr ; // FlushDataCache Function 15 | u32 HomeFSReadAddr ; 16 | u32 HomeFSUHandleAddr; 17 | u32 HomeCardUpdateInitAddr; 18 | u32 HomeAptStartAppletAddr ; 19 | 20 | u32 KProcessHandleDataOffset; 21 | u32 KProcessPIDOffset; 22 | u32 KProcessCodesetOffset; 23 | u32 ControlMemoryPatchAddr1; 24 | u32 ControlMemoryPatchAddr2; 25 | u32 KernelFreeSpaceAddr_Optional; 26 | u32 KMMUHaxAddr; 27 | u32 KMMUHaxSize; 28 | u32 InterProcessDmaFinishState; 29 | u32 fsUserHandle; 30 | u32 arm11BinStart; 31 | u32 arm11BinSize; 32 | u32 ShowDbgFunc; 33 | } NTR_CONFIG; 34 | 35 | typedef struct _BOOTNTR_CONFIG { 36 | u32 FSPatchAddr; 37 | u32 SMPatchAddr; 38 | u32 SvcPatchAddr; 39 | u32 FSPid; 40 | u32 SMPid; 41 | u32 requireKernelHax; 42 | } BOOTNTR_CONFIG; -------------------------------------------------------------------------------- /lib/ctrcommon/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Steveice10 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /lib/ctrcommon/data/ctrcommon_shader.vsh: -------------------------------------------------------------------------------- 1 | ; setup constants 2 | .const c20, 1.0, 1.0, 1.0, 1.0 3 | 4 | ; setup outmap 5 | .out o0, result.position, 0xF 6 | .out o1, result.color, 0xF 7 | .out o2, result.texcoord0, 0x3 8 | 9 | ; setup uniform map (not required) 10 | .uniform c0, c3, projection 11 | .uniform c4, c7, modelview 12 | 13 | .vsh vmain, end_vmain 14 | 15 | ; code 16 | vmain: 17 | ; temp = modelview * in.pos 18 | dp4 r0, c4, v0 (0x0) 19 | dp4 r0, c5, v0 (0x1) 20 | dp4 r0, c6, v0 (0x2) 21 | mov r0, c20 (0x3) 22 | ; result.pos = projection * temp 23 | dp4 o0, c0, r0 (0x0) 24 | dp4 o0, c1, r0 (0x1) 25 | dp4 o0, c2, r0 (0x2) 26 | dp4 o0, c3, r0 (0x3) 27 | ; result.color = in.color 28 | mov o1, v2 (0x5) 29 | ; result.texcoord = in.texcoord 30 | mov o2, v1 (0x5) 31 | ; end 32 | nop 33 | end 34 | end_vmain: 35 | 36 | ; operand descriptors 37 | .opdesc x___, xyzw, xyzw ; 0x0 38 | .opdesc _y__, xyzw, xyzw ; 0x1 39 | .opdesc __z_, xyzw, xyzw ; 0x2 40 | .opdesc ___w, xyzw, xyzw ; 0x3 41 | .opdesc xyz_, xyzw, xyzw ; 0x4 42 | .opdesc xyzw, xyzw, xyzw ; 0x5 43 | .opdesc x_zw, xyzw, xyzw ; 0x6 44 | .opdesc xyzw, yyyw, xyzw ; 0x7 45 | .opdesc xyz_, wwww, wwww ; 0x8 46 | .opdesc xyz_, yyyy, xyzw ; 0x9 47 | -------------------------------------------------------------------------------- /source/misc.s: -------------------------------------------------------------------------------- 1 | 2 | .global backdoorHandler 3 | .type backdoorHandler, %function 4 | backdoorHandler: 5 | ldr r3, [sp] 6 | push {lr} 7 | str sp, [r3, #-0x4]! 8 | mov sp, r3 9 | bl kernelCallback 10 | ldr r3, [sp], #4 11 | mov sp, r3 12 | pop {pc} 13 | 14 | .global InvalidateEntireInstructionCache 15 | .type InvalidateEntireInstructionCache, %function 16 | InvalidateEntireInstructionCache: 17 | mov r0, #0 18 | mcr p15, 0, r0, c7, c5, 0 19 | bx lr 20 | 21 | .global InvalidateEntireDataCache 22 | .type InvalidateEntireDataCache, %function 23 | InvalidateEntireDataCache: 24 | mov r0, #0 25 | mcr p15, 0, r0, c7, c10, 0 26 | bx lr 27 | 28 | .global FlushAllCache 29 | .type FlushAllCache, %function 30 | FlushAllCache: 31 | mov r0, #0 32 | mcr p15, 0, r0, c7, c14, 0 @Clean and Invalidate Entire Data Cache 33 | mcr p15, 0, r0, c7, c5, 0 @Invalidate Entire Instruction Cache. Also flushes the branch target cache 34 | mcr p15, 0, R0,c7,c10, 4 @Data Synchronization Barrier 35 | mcr p15, 0, R0,c7,c5, 4 @Flush Prefetch Buffer 36 | bx lr 37 | 38 | _flushEntireDataCache: 39 | MOV R0, #0 40 | MCR p15, 0, R0, c7, c14, 0 41 | MCR p15, 0, R0, c7, c10, 4 42 | BX LR 43 | .global kFlushDataCache 44 | .type kFlushDataCache, %function 45 | kFlushDataCache: 46 | CMP R1, #0x4000 47 | BCS _flushEntireDataCache 48 | BIC R2, R0, #0x1F 49 | ADD R0, R0, R1 50 | ADD R0, R0, #0x1F 51 | BIC R0, R0, #0x1F 52 | CMP R2, R0 53 | BCS _flushDataCache_end 54 | 1: 55 | MCR p15, 0, R2, c7, c14, 1 56 | ADD R2, R2, #0x20 57 | CMP R2, R0 58 | BCC 1b 59 | _flushDataCache_end: 60 | MOV R0, #0 61 | MCR p15, 0, R0, c7, c10, 4 62 | BX LR -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/input.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_INPUT_HPP__ 2 | #define __CTRCOMMON_INPUT_HPP__ 3 | 4 | #include 5 | 6 | #ifndef BIT 7 | #define BIT(n) (1U << (n)) 8 | #define BIT_SELF_DEFINED 9 | #endif 10 | typedef enum { 11 | BUTTON_NONE = 0, 12 | BUTTON_A = BIT(0), 13 | BUTTON_B = BIT(1), 14 | BUTTON_SELECT = BIT(2), 15 | BUTTON_START = BIT(3), 16 | BUTTON_DRIGHT = BIT(4), 17 | BUTTON_DLEFT = BIT(5), 18 | BUTTON_DUP = BIT(6), 19 | BUTTON_DDOWN = BIT(7), 20 | BUTTON_R = BIT(8), 21 | BUTTON_L = BIT(9), 22 | BUTTON_X = BIT(10), 23 | BUTTON_Y = BIT(11), 24 | BUTTON_ZL = BIT(14), 25 | BUTTON_ZR = BIT(15), 26 | BUTTON_TOUCH = BIT(20), 27 | BUTTON_CSTICK_RIGHT = BIT(24), 28 | BUTTON_CSTICK_LEFT = BIT(25), 29 | BUTTON_CSTICK_UP = BIT(26), 30 | BUTTON_CSTICK_DOWN = BIT(27), 31 | BUTTON_CPAD_RIGHT = BIT(28), 32 | BUTTON_CPAD_LEFT = BIT(29), 33 | BUTTON_CPAD_UP = BIT(30), 34 | BUTTON_CPAD_DOWN = BIT(31), 35 | BUTTON_UP = BUTTON_DUP | BUTTON_CPAD_UP, 36 | BUTTON_DOWN = BUTTON_DDOWN | BUTTON_CPAD_DOWN, 37 | BUTTON_LEFT = BUTTON_DLEFT | BUTTON_CPAD_LEFT, 38 | BUTTON_RIGHT = BUTTON_DRIGHT | BUTTON_CPAD_RIGHT, 39 | } Button; 40 | #ifdef BIT_SELF_DEFINED 41 | #undef BIT 42 | #undef BIT_SELF_DEFINED 43 | #endif 44 | 45 | typedef struct { 46 | int x; 47 | int y; 48 | } Touch; 49 | 50 | const std::string inputGetButtonName(Button button); 51 | void inputPoll(); 52 | bool inputIsAnyPressed(); 53 | Button inputGetAnyPressed(); 54 | bool inputIsReleased(Button button); 55 | bool inputIsPressed(Button button); 56 | bool inputIsHeld(Button button); 57 | Touch inputGetTouch(); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/ui.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_UI_HPP__ 2 | #define __CTRCOMMON_UI_HPP__ 3 | 4 | #include "ctrcommon/app.hpp" 5 | #include "ctrcommon/gpu.hpp" 6 | #include "ctrcommon/types.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct { 13 | std::string id; 14 | std::string name; 15 | std::vector details; 16 | } SelectableElement; 17 | 18 | typedef struct { 19 | FILE* fd; 20 | u64 fileSize; 21 | } RemoteFile; 22 | 23 | bool uiSelect(SelectableElement* selected, std::vector elements, std::function &currElements, SelectableElement currElement, bool &elementsDirty, bool &resetCursorIfDirty)> onLoop, std::function onSelect, bool useTopScreen = true, bool alphabetize = true, bool dpadPageScroll = true); 24 | bool uiSelectFile(std::string* selectedFile, const std::string rootDirectory, std::vector extensions, std::function onLoop, std::function onSelect, bool useTopScreen = true, bool dpadPageScroll = true); 25 | bool uiSelectApp(App* selectedApp, MediaType mediaType, std::function onLoop, std::function onSelect, bool useTopScreen = true, bool dpadPageScroll = true); 26 | void uiDisplayMessage(Screen screen, const std::string message); 27 | bool uiPrompt(Screen screen, const std::string message, bool question); 28 | void uiDisplayProgress(Screen screen, const std::string operation, const std::string details, bool quickSwap, u32 progress); 29 | RemoteFile uiAcceptRemoteFile(Screen screen, std::function onWait = [&](std::stringstream& infoStream){}); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/app.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_APP_HPP__ 2 | #define __CTRCOMMON_APP_HPP__ 3 | 4 | #include "ctrcommon/fs.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | typedef enum { 11 | PLATFORM_WII, 12 | PLATFORM_DSI, 13 | PLATFORM_3DS, 14 | PLATFORM_WIIU, 15 | PLATFORM_UNKNOWN 16 | } AppPlatform; 17 | 18 | // TODO: verify categories. 19 | typedef enum { 20 | CATEGORY_APP, 21 | CATEGORY_DEMO, 22 | CATEGORY_DLC, 23 | CATEGORY_PATCH, 24 | CATEGORY_SYSTEM, 25 | CATEGORY_TWL 26 | } AppCategory; 27 | 28 | typedef struct { 29 | u64 titleId; 30 | u32 uniqueId; 31 | char productCode[16]; 32 | MediaType mediaType; 33 | AppPlatform platform; 34 | AppCategory category; 35 | u16 version; 36 | u64 size; 37 | } App; 38 | 39 | typedef enum { 40 | APP_SUCCESS, 41 | APP_PROCESS_CLOSING, 42 | APP_OPERATION_CANCELLED, 43 | APP_AM_INIT_FAILED, 44 | APP_IO_ERROR, 45 | APP_OPEN_FILE_FAILED, 46 | APP_BEGIN_INSTALL_FAILED, 47 | APP_INSTALL_ERROR, 48 | APP_FINALIZE_INSTALL_FAILED, 49 | APP_DELETE_FAILED, 50 | APP_LAUNCH_FAILED 51 | } AppResult; 52 | 53 | const std::string appGetResultString(AppResult result); 54 | const std::string appGetPlatformName(AppPlatform platform); 55 | const std::string appGetCategoryName(AppCategory category); 56 | App appGetCiaInfo(const std::string file, MediaType mediaType); 57 | bool appIsInstalled(App app); 58 | std::vector appList(MediaType mediaType); 59 | AppResult appInstallFile(MediaType mediaType, const std::string path, std::function onProgress); 60 | AppResult appInstall(MediaType mediaType, FILE* fd, u64 size, std::function onProgress); 61 | AppResult appDelete(App app); 62 | AppResult appLaunch(App app); 63 | 64 | #endif -------------------------------------------------------------------------------- /source/ns.h: -------------------------------------------------------------------------------- 1 | #define NS_DEFAULT_MEM_REGION 0x300 2 | 3 | #define DEBUG_BUFFER_SIZE 0x4000 4 | #define GLOBAL_BUFFER_SIZE 0x4000 5 | #define MAX_BREAKPOINT 64 6 | 7 | typedef struct _RT_LOCK { 8 | vu32 value; 9 | } RT_LOCK; 10 | 11 | 12 | #define NS_CONFIGURE_ADDR 0x06000000 13 | 14 | typedef struct _RT_HOOK { 15 | u32 model; 16 | u32 isEnabled; 17 | u32 funcAddr; 18 | u32 bakCode[16]; 19 | u32 jmpCode[16]; 20 | u32 callCode[16]; 21 | } RT_HOOK; 22 | 23 | typedef struct _NS_BREAKPOINT { 24 | u32 type; 25 | u32 flag; 26 | u32 addr; 27 | RT_HOOK hook; 28 | u32 stubCode[32]; 29 | u32 isEnabled; 30 | } NS_BREAKPOINT; 31 | 32 | 33 | 34 | typedef struct _NS_CONFIG { 35 | u32 initMode; 36 | u32 startupCommand; 37 | u32 hSOCU; 38 | 39 | u8* debugBuf; 40 | u32 debugBufSize; 41 | u32 debugPtr; 42 | u32 debugReady; 43 | 44 | RT_LOCK debugBufferLock; 45 | 46 | u32 startupInfo[32]; 47 | u32 allowDirectScreenAccess; 48 | u32 exitFlag; 49 | 50 | u32 sharedFunc[100]; 51 | 52 | } NS_CONFIG; 53 | 54 | 55 | 56 | void nsDbgPrint (const char* fmt, ... ); 57 | 58 | void rtInitLock(RT_LOCK *lock) ; 59 | void rtAcquireLock(RT_LOCK *lock) ; 60 | void rtReleaseLock(RT_LOCK *lock) ; 61 | u32 rtAlignToPageSize(u32 size); 62 | u32 rtGetPageOfAddress(u32 addr) ; 63 | u32 rtCheckRemoteMemoryRegionSafeForWrite(Handle hProcess, u32 addr, u32 size) ; 64 | u32 rtSafeCopyMemory(u32 dst, u32 src, u32 size) ; 65 | int rtRecvSocket(u32 sockfd, u8 *buf, int size); 66 | int rtSendSocket(u32 sockfd, u8 *buf, int size); 67 | u16 rtIntToPortNumber(u16 x) ; 68 | u32 rtGetFileSize(u8* fileName); 69 | u32 rtLoadFileToBuffer(u8* fileName, u32* pBuf, u32 bufSize) ; 70 | u32 rtGetThreadReg(Handle hProcess, u32 tid, u32* ctx); 71 | u32 rtFlushInstructionCache(void* ptr, u32 size); 72 | void rtInitHook(RT_HOOK* hook, u32 funcAddr, u32 callbackAddr); 73 | void rtEnableHook(RT_HOOK* hook); 74 | void rtDisableHook(RT_HOOK* hook); 75 | u32 rtGenerateJumpCode(u32 dst, u32* buf); 76 | 77 | 78 | u32 nsAttachProcess(Handle hProcess, u32 remotePC, NS_CONFIG *cfg) ; 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /source/mysvcs.h: -------------------------------------------------------------------------------- 1 | 2 | Result svc_getDmaState(u32* state, Handle dma); 3 | Result svc_startInterProcessDma(Handle* hdma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, u32* config); 4 | 5 | Result svc_writeProcessMemory(Handle debug, void const* buffer, u32 addr, u32 size); 6 | Result svc_readProcessMemory(void* buffer, Handle debug, u32 addr, u32 size); 7 | Result svc_debugActiveProcess(s32* handle_out, u32 pid); 8 | Result svc_getProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount); 9 | 10 | Result svc_controlProcessMemory(Handle hProcess, void* Addr0, void* Addr1, u32 size, u32 Type, u32 Permissions); 11 | 12 | Result svc_openProcess(Handle* process, u32 processId); 13 | Result svc_addCodeSegment(u32 addr, u32 size); 14 | Result svc_flushProcessDataCache(Handle handle, u32 addr, u32 size); 15 | Result svc_invalidateProcessDataCache(Handle handle, u32 addr, u32 size); 16 | Result svc_controlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 permissions); //(outaddr is usually the same as the input addr0) 17 | void svc_exitProcess(void); 18 | Result svc_backDoor(void* backdoorHandler); 19 | Result svc_createThread(Handle* thread, ThreadFunc entrypoint, u32 arg, u32* stacktop, s32 threadpriority, s32 processorid); 20 | void svc_exitThread(); 21 | void svc_sleepThread(s64 ns); 22 | Result svc_createMutex(Handle* mutex, bool initialLocked); 23 | Result svc_releaseMutex(Handle handle); 24 | Result svc_releaseSemaphore(s32* count, Handle semaphore, s32 releaseCount); 25 | Result svc_createEvent(Handle* event, u8 resettype); 26 | Result svc_signalEvent(Handle handle); 27 | Result svc_clearEvent(Handle handle); 28 | Result svc_createMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 mypermission, u32 otherpermission); 29 | Result svc_mapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission); 30 | Result svc_unmapMemoryBlock(Handle memblock, u32 addr); 31 | Result svc_waitSynchronization1(Handle handle, s64 nanoseconds); 32 | Result svc_waitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 nanoseconds); 33 | Result svc_arbitrateAddress(Handle arbiter, u32 addr, u8 type, s32 value, s64 nanoseconds); 34 | Result svc_closeHandle(Handle handle); 35 | u64 svc_getSystemTick(); 36 | Result svc_getSystemInfo(s64* out, u32 type, s32 param); 37 | Result svc_connectToPort(volatile Handle* out, const char* portName); 38 | Result svc_sendSyncRequest(Handle session); 39 | Result svc_getProcessId(u32 *out, Handle handle); 40 | Result svc_getThreadId(u32 *out, Handle handle); 41 | Result svc_setThreadIdealProcessor(Handle handle, u32 processorid); -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/fs.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/fs.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include <3ds.h> 12 | 13 | u64 fsGetFreeSpace(MediaType mediaType) { 14 | u32 clusterSize; 15 | u32 freeClusters; 16 | Result res = 0; 17 | if(mediaType == NAND) { 18 | res = FSUSER_GetNandArchiveResource(NULL, NULL, &clusterSize, NULL, &freeClusters); 19 | } else { 20 | res = FSUSER_GetSdmcArchiveResource(NULL, NULL, &clusterSize, NULL, &freeClusters); 21 | } 22 | 23 | if(res != 0) { 24 | platformSetError(serviceParseError((u32) res)); 25 | return 0; 26 | } 27 | 28 | return (u64) clusterSize * (u64) freeClusters; 29 | } 30 | 31 | bool fsExists(const std::string path) { 32 | FILE* fd = fopen(path.c_str(), "r"); 33 | if(fd) { 34 | fclose(fd); 35 | return true; 36 | } 37 | 38 | return fsIsDirectory(path); 39 | } 40 | 41 | bool fsIsDirectory(const std::string path) { 42 | DIR* dir = opendir(path.c_str()); 43 | if(dir) { 44 | closedir(dir); 45 | return true; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | std::string fsGetExtension(const std::string path) { 52 | std::string::size_type dotPos = path.rfind('.'); 53 | if(dotPos == std::string::npos) { 54 | return ""; 55 | } 56 | 57 | return path.substr(dotPos + 1); 58 | } 59 | 60 | bool fsHasExtension(const std::string path, const std::string extension) { 61 | std::string::size_type dotPos = path.rfind('.'); 62 | return dotPos != std::string::npos && path.substr(dotPos + 1).compare(extension) == 0; 63 | } 64 | 65 | bool fsHasExtensions(const std::string path, const std::vector extensions) { 66 | std::string extension = fsGetExtension(path); 67 | return extensions.empty() || (extension.compare("") != 0 && std::find(extensions.begin(), extensions.end(), extension) != extensions.end()); 68 | } 69 | 70 | std::vector fsGetDirectoryContents(const std::string directory) { 71 | std::vector result; 72 | bool hasSlash = directory.size() != 0 && directory[directory.size() - 1] == '/'; 73 | const std::string dirWithSlash = hasSlash ? directory : directory + "/"; 74 | 75 | DIR* dir = opendir(dirWithSlash.c_str()); 76 | if(dir == NULL) { 77 | return result; 78 | } 79 | 80 | while(true) { 81 | struct dirent* ent = readdir(dir); 82 | if(ent == NULL) { 83 | break; 84 | } 85 | 86 | result.push_back({dirWithSlash + std::string(ent->d_name), std::string(ent->d_name)}); 87 | } 88 | 89 | closedir(dir); 90 | return result; 91 | } 92 | -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/sound.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/sound.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include <3ds.h> 6 | 7 | void* soundAlloc(u32 size) { 8 | return linearAlloc(size); 9 | } 10 | 11 | void soundFree(void* mem) { 12 | linearFree(mem); 13 | } 14 | 15 | bool soundPlay(u32 channel, void *samples, u32 numSamples, SampleFormat format, u32 sampleRate, float leftVolume, float rightVolume, bool loop) { 16 | if(samples == NULL || !serviceRequire("csnd")) { 17 | return false; 18 | } 19 | 20 | u32 chn = 8 + channel; 21 | u32 flags = (format == SAMPLE_PCM16 ? SOUND_FORMAT_16BIT : SOUND_FORMAT_8BIT) | (loop ? SOUND_REPEAT : SOUND_ONE_SHOT); 22 | u32 size = numSamples * (format == SAMPLE_PCM16 ? 2 : 1); 23 | 24 | if(!(csndChannels & BIT(chn))) { 25 | return false; 26 | } 27 | 28 | if(leftVolume < 0) { 29 | leftVolume = 0; 30 | } else if(leftVolume > 1) { 31 | leftVolume = 1; 32 | } 33 | 34 | if(rightVolume < 0) { 35 | rightVolume = 0; 36 | } else if(rightVolume > 1) { 37 | rightVolume = 1; 38 | } 39 | 40 | GSPGPU_FlushDataCache(NULL, (u8*) samples, size); 41 | 42 | u32 paddr0 = 0; 43 | u32 paddr1 = 0; 44 | u32 encoding = (flags >> 12) & 3; 45 | if(encoding != CSND_ENCODING_PSG) { 46 | paddr0 = osConvertVirtToPhys((u32) samples); 47 | paddr1 = osConvertVirtToPhys((u32) samples); 48 | if(encoding == CSND_ENCODING_ADPCM) { 49 | int adpcmSample = ((s16*) samples)[-2]; 50 | int adpcmIndex = ((u8*) samples)[-2]; 51 | CSND_SetAdpcmState(chn, 0, adpcmSample, adpcmIndex); 52 | } 53 | } 54 | 55 | u32 timer = CSND_TIMER(sampleRate); 56 | if(timer < 0x0042) { 57 | timer = 0x0042; 58 | } else if(timer > 0xFFFF) { 59 | timer = 0xFFFF; 60 | } 61 | 62 | flags &= ~0xFFFF001F; 63 | flags |= SOUND_ENABLE | SOUND_CHANNEL(chn) | (timer << 16); 64 | 65 | u32 volumes = (u32) (leftVolume * 0x8000) | ((u32) (rightVolume * 0x8000) << 16); 66 | CSND_SetChnRegs(flags, paddr0, paddr1, size, volumes, volumes); 67 | 68 | u32 loopMode = (flags >> 10) & 3; 69 | if(loopMode == CSND_LOOPMODE_NORMAL && paddr1 > paddr0) { 70 | size -= paddr1 - paddr0; 71 | CSND_SetBlock(chn, 1, paddr1, size); 72 | } 73 | 74 | CSND_SetPlayState(chn, 1); 75 | return true; 76 | } 77 | 78 | bool soundStop(u32 channel) { 79 | if(!serviceRequire("csnd")) { 80 | return false; 81 | } 82 | 83 | u32 chn = 8 + channel; 84 | if(!(csndChannels & BIT(chn))) { 85 | return false; 86 | } 87 | 88 | CSND_SetPlayState(chn, 0); 89 | return true; 90 | } 91 | 92 | bool soundFlush() { 93 | if(!serviceRequire("csnd")) { 94 | return false; 95 | } 96 | 97 | Result result = csndExecCmds(0); 98 | if(result != 0) { 99 | platformSetError(serviceParseError((u32) result)); 100 | } 101 | 102 | return result == 0; 103 | } -------------------------------------------------------------------------------- /tools/locate_offsets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import sys 4 | import os.path 5 | import re 6 | 7 | # Data at offsets of dbgKernelCacheInterface addresses for o3ds 8 | dbgKernelCacheInterfaceDataOld3DS = ( 9 | "\xF8\x43\x2D\xE9\x1A\x0B\x51\xE3\x01\x70\x80\xE0\x1F\x80\x87\xE2", 10 | "\xF8\x40\x2D\xE9\x01\x20\x80\xE0\x1F\x20\x82\xE2\x01\x09\x51\xE3\x00\x60\xA0\xE3\x1F\x50\xC2\xE3\x1F\x40\xC0\xE3\x0E\x00\x00\x2A\x05\x30\xA0\xE1\x04\x20\xA0\xE1\x01", 11 | "\xF8\x40\x2D\xE9\x01\x20\x80\xE0\x1F\x20\x82\xE2\x01\x09\x51\xE3\x00\x60\xA0\xE3\x1F\x50\xC2\xE3\x1F\x40\xC0\xE3\x0E\x00\x00\x2A\x05\x30\xA0\xE1\x04\x20\xA0\xE1\x02", 12 | "\xF8\x40\x2D\xE9\x01\x20\x80\xE0\x1F\x20\x82\xE2\x1A\x0B\x51" 13 | ) 14 | 15 | # Data at offsets of dbgKernelCacheInterface for n3dss 16 | dbgKernelCacheInterfaceDataNew3DS = ( 17 | "\xF8\x4F\x2D\xE9\x00\x40\xA0\xE1\x01\x90\xA0\xE1\x0C\x11\x9F", 18 | "\xF8\x40\x2D\xE9\x01\x20\x80\xE0\x1F\x20\x82\xE2\x01\x09\x51", 19 | "\xF8\x43\x2D\xE9\x01\x90\xA0\xE1\x10\x11\x9F\xE5\x09\x20\x80", 20 | "\xF8\x40\x2D\xE9\x01\x20\x80\xE0\x1F\x20\x82\xE2\x1A\x0B\x51" 21 | ) 22 | 23 | 24 | # Empty array where cache interface offsets will go 25 | dbgKernelCacheInterfaceOffsets = ["","","",""] 26 | 27 | # If not all arguments are provided, print out a "helpful" message 28 | if len(sys.argv) < 3: 29 | print "Usage: finder.py \n" 30 | print "Example: finder.py axiwramp.dmp o3ds" 31 | sys.exit() 32 | 33 | # set file_path equal to the first argument and console_type to the second. Lowercase console_type in case some people use N3DS or similar over n3ds 34 | file_path = sys.argv[1] 35 | console_type = sys.argv[2].lower() 36 | 37 | # Check if dump exists; if it does, use it, otherwise say file not found 38 | if os.path.isfile(file_path): 39 | f = open(file_path, "rb") 40 | data = f.read() 41 | f.close() 42 | 43 | if console_type == "o3ds": 44 | for index, searchString in enumerate(dbgKernelCacheInterfaceDataOld3DS): 45 | dbgKernelCacheInterfaceOffsets[index] = data.find(searchString) 46 | elif console_type == "n3ds": 47 | for index, searchString in enumerate(dbgKernelCacheInterfaceDataNew3DS): 48 | dbgKernelCacheInterfaceOffsets[index] = data.find(searchString) 49 | else: 50 | print "Invalid console tpye! Valid console types: o3ds, n3ds" 51 | sys.exit() 52 | 53 | for index, offset in enumerate(dbgKernelCacheInterfaceOffsets): 54 | print "DEBUG:", offset 55 | if offset > 385024: # If offset is greater than 385024 (0x5E000 in decimal), then it's in a different memory mapping - adjust accordingly. 56 | dbgKernelCacheInterfaceOffsets[index] = hex(offset + 4293668864) # offset plus 0xFFEC3000 in decimal 57 | else: 58 | dbgKernelCacheInterfaceOffsets[index] = hex(offset + 4293918720) # offset plus 0xFFF20000 in decimal 59 | 60 | if console_type == "o3ds": 61 | print "dbgKernelCacheInterface cacheInterface_OldVER = {" 62 | print "\t//for old 3ds VER" 63 | else: 64 | print "dbgKernelCacheInterface cacheInterface_NEWVER = {" 65 | print "\t//for new 3ds VER" 66 | 67 | for index, offset in enumerate(dbgKernelCacheInterfaceOffsets): 68 | if index != 3: 69 | print "\t(void*)" + offset.upper() + "," 70 | else: 71 | print "\t(void*)" + offset.upper() 72 | print "}" 73 | else: 74 | print "File not found!" -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/input.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/input.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include <3ds.h> 6 | 7 | const std::string inputGetButtonName(Button button) { 8 | if(button == BUTTON_NONE) { 9 | return "None"; 10 | } else if(button == BUTTON_A) { 11 | return "A"; 12 | } else if(button == BUTTON_B) { 13 | return "B"; 14 | } else if(button == BUTTON_SELECT) { 15 | return "Select"; 16 | } else if(button == BUTTON_START) { 17 | return "Start"; 18 | } else if(button == BUTTON_DRIGHT) { 19 | return "DPad Right"; 20 | } else if(button == BUTTON_DLEFT) { 21 | return "DPad Left"; 22 | } else if(button == BUTTON_DUP) { 23 | return "DPad Up"; 24 | } else if(button == BUTTON_DDOWN) { 25 | return "DPad Down"; 26 | } else if(button == BUTTON_R) { 27 | return "R"; 28 | } else if(button == BUTTON_L) { 29 | return "L"; 30 | } else if(button == BUTTON_X) { 31 | return "X"; 32 | } else if(button == BUTTON_Y) { 33 | return "Y"; 34 | } else if(button == BUTTON_ZL) { 35 | return "ZL"; 36 | } else if(button == BUTTON_ZR) { 37 | return "ZR"; 38 | } else if(button == BUTTON_TOUCH) { 39 | return "Touch"; 40 | } else if(button == BUTTON_CSTICK_RIGHT) { 41 | return "CStick Right"; 42 | } else if(button == BUTTON_CSTICK_LEFT) { 43 | return "CStick Left"; 44 | } else if(button == BUTTON_CSTICK_UP) { 45 | return "CStick Up"; 46 | } else if(button == BUTTON_CSTICK_DOWN) { 47 | return "CStick Down"; 48 | } else if(button == BUTTON_CPAD_RIGHT) { 49 | return "CirclePad Right"; 50 | } else if(button == BUTTON_CPAD_LEFT) { 51 | return "CirclePad Left"; 52 | } else if(button == BUTTON_CPAD_UP) { 53 | return "CirclePad Up"; 54 | } else if(button == BUTTON_CPAD_DOWN) { 55 | return "CirclePad Down"; 56 | } else if(button == BUTTON_UP) { 57 | return "Up"; 58 | } else if(button == BUTTON_DOWN) { 59 | return "Down"; 60 | } else if(button == BUTTON_LEFT) { 61 | return "Left"; 62 | } else if(button == BUTTON_RIGHT) { 63 | return "Right"; 64 | } 65 | 66 | return "Unknown Button"; 67 | } 68 | 69 | void inputPoll() { 70 | hidScanInput(); 71 | } 72 | 73 | bool inputIsAnyPressed() { 74 | for(u32 button = 0; button < 32; button++) { 75 | if(inputIsPressed((Button) (1 << button))) { 76 | return true; 77 | } 78 | } 79 | 80 | return false; 81 | } 82 | 83 | Button inputGetAnyPressed() { 84 | for(u32 button = 0; button < 32; button++) { 85 | if(inputIsPressed((Button) (1 << button))) { 86 | return (Button) (1 << button); 87 | } 88 | } 89 | 90 | return (Button) -1; 91 | } 92 | 93 | bool inputIsReleased(Button button) { 94 | return (hidKeysUp() & button) != 0; 95 | } 96 | 97 | bool inputIsPressed(Button button) { 98 | return (hidKeysDown() & button) != 0; 99 | } 100 | 101 | bool inputIsHeld(Button button) { 102 | return (hidKeysHeld() & button) != 0; 103 | } 104 | 105 | Touch inputGetTouch() { 106 | touchPosition pos; 107 | hidTouchRead(&pos); 108 | return {pos.px, pos.py}; 109 | } -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/socket.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/socket.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include <3ds.h> 12 | 13 | u64 htonll(u64 value) { 14 | static const int num = 42; 15 | if(*((char*) &num) == num) { 16 | return (((uint64_t) htonl((u32) value)) << 32) + htonl((u32) (value >> 32)); 17 | } else { 18 | return value; 19 | } 20 | } 21 | 22 | u64 ntohll(u64 value) { 23 | return htonll(value); 24 | } 25 | 26 | u32 socketGetHostIP() { 27 | if(!serviceRequire("soc")) { 28 | return 0; 29 | } 30 | 31 | return (u32) gethostid(); 32 | } 33 | 34 | int socketListen(u16 port) { 35 | if(!serviceRequire("soc")) { 36 | return -1; 37 | } 38 | 39 | int fd = socket(AF_INET, SOCK_STREAM, 0); 40 | if(fd < 0) { 41 | return -1; 42 | } 43 | 44 | struct sockaddr_in address; 45 | memset(&address, 0, sizeof(address)); 46 | address.sin_family = AF_INET; 47 | address.sin_addr.s_addr = htonl(INADDR_ANY); 48 | address.sin_port = htons(port); 49 | 50 | if(bind(fd, (struct sockaddr*) &address, sizeof(address)) != 0) { 51 | closesocket(fd); 52 | return -1; 53 | } 54 | 55 | int flags = fcntl(fd, F_GETFL); 56 | if(flags == -1) { 57 | closesocket(fd); 58 | return -1; 59 | } 60 | 61 | if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { 62 | closesocket(fd); 63 | return -1; 64 | } 65 | 66 | if(listen(fd, 10) != 0) { 67 | closesocket(fd); 68 | return -1; 69 | } 70 | 71 | return fd; 72 | } 73 | 74 | FILE* socketAccept(int listeningSocket, std::string* acceptedIp) { 75 | if(!serviceRequire("soc")) { 76 | return NULL; 77 | } 78 | 79 | struct sockaddr_in addr; 80 | socklen_t addrSize = sizeof(addr); 81 | int afd = accept(listeningSocket, (struct sockaddr*) &addr, &addrSize); 82 | if(afd < 0) { 83 | return NULL; 84 | } 85 | 86 | if(acceptedIp != NULL) { 87 | *acceptedIp = inet_ntoa(addr.sin_addr); 88 | } 89 | 90 | int flags = fcntl(afd, F_GETFL); 91 | if(flags == -1) { 92 | closesocket(afd); 93 | return NULL; 94 | } 95 | 96 | if(fcntl(afd, F_SETFL, flags | O_NONBLOCK) != 0) { 97 | closesocket(afd); 98 | return NULL; 99 | } 100 | 101 | return fdopen(afd, "rw"); 102 | } 103 | 104 | FILE* socketConnect(const std::string ipAddress, u16 port, int timeout) { 105 | if(!serviceRequire("soc")) { 106 | return NULL; 107 | } 108 | 109 | int fd = socket(AF_INET, SOCK_STREAM, 0); 110 | if(fd < 0) { 111 | return NULL; 112 | } 113 | 114 | int flags = fcntl(fd, F_GETFL); 115 | if(flags == -1) { 116 | closesocket(fd); 117 | return NULL; 118 | } 119 | 120 | if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { 121 | closesocket(fd); 122 | return NULL; 123 | } 124 | 125 | struct sockaddr_in address; 126 | memset(&address, 0, sizeof(address)); 127 | address.sin_family = AF_INET; 128 | address.sin_port = htons(port); 129 | 130 | if(inet_aton(ipAddress.c_str(), &address.sin_addr) <= 0) { 131 | closesocket(fd); 132 | return NULL; 133 | } 134 | 135 | if(connect(fd, (struct sockaddr*) &address, sizeof(address)) < 0) { 136 | if(errno != EINPROGRESS) { 137 | closesocket(fd); 138 | return NULL; 139 | } 140 | } 141 | 142 | struct pollfd pollinfo; 143 | pollinfo.fd = fd; 144 | pollinfo.events = POLLOUT; 145 | pollinfo.revents = 0; 146 | int pollRet = poll(&pollinfo, 1, timeout > 0 ? timeout * 1000 : timeout); 147 | if(pollRet <= 0) { 148 | if(pollRet == 0) { 149 | errno = ETIMEDOUT; 150 | } 151 | 152 | closesocket(fd); 153 | return NULL; 154 | } 155 | 156 | return fdopen(fd, "rw"); 157 | } -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/service.cpp: -------------------------------------------------------------------------------- 1 | #include "service.hpp" 2 | 3 | #include "../libkhax/khax.h" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include <3ds.h> 12 | 13 | #define GET_BITS(v, s, e) (((v) >> (s)) & ((1 << ((e) - (s) + 1)) - 1)) 14 | 15 | static u32* socBuffer; 16 | 17 | Result socInit() { 18 | socBuffer = (u32*) memalign(0x1000, 0x100000); 19 | if(socBuffer == NULL) { 20 | return -1; 21 | } 22 | 23 | Result socResult = SOC_Initialize(socBuffer, 0x100000); 24 | if(socResult != 0) { 25 | free(socBuffer); 26 | socBuffer = NULL; 27 | return socResult; 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | void socCleanup() { 34 | SOC_Shutdown(); 35 | if(socBuffer != NULL) { 36 | free(socBuffer); 37 | socBuffer = NULL; 38 | } 39 | } 40 | 41 | static u32* irBuffer; 42 | 43 | Result irInit() { 44 | irBuffer = (u32*) memalign(0x1000, 0x1000); 45 | if(irBuffer == NULL) { 46 | return -1; 47 | } 48 | 49 | Result irResult = IRU_Initialize(irBuffer, 0x1000); 50 | if(irResult != 0) { 51 | free(irBuffer); 52 | irBuffer = NULL; 53 | return irResult; 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | void irCleanup() { 60 | IRU_Shutdown(); 61 | if(irBuffer != NULL) { 62 | free(irBuffer); 63 | irBuffer = NULL; 64 | } 65 | } 66 | 67 | static std::map> services; 68 | 69 | void serviceCleanup() { 70 | for(std::map>::iterator it = services.begin(); it != services.end(); it++) { 71 | if((*it).second != NULL) { 72 | (*it).second(); 73 | } 74 | } 75 | 76 | services.clear(); 77 | } 78 | 79 | bool serviceCheckNew3DS() { 80 | if(osGetKernelVersion() >= SYSTEM_VERSION(2, 44, 6)) { 81 | u8 isNew3DS = 0; 82 | Result result = APT_CheckNew3DS(NULL, &isNew3DS); 83 | if(result == 0) { 84 | return isNew3DS != 0; 85 | } 86 | } 87 | 88 | return false; 89 | } 90 | 91 | bool serviceRequire(const std::string service) { 92 | if(services.find(service) != services.end()) { 93 | return true; 94 | } 95 | 96 | Result result = 0; 97 | std::function cleanup = NULL; 98 | if(service.compare("gfx") == 0) { 99 | result = (gfxInitDefault(), 0); 100 | cleanup = &gfxExit; 101 | } else if(service.compare("soc") == 0) { 102 | result = socInit(); 103 | cleanup = &socCleanup; 104 | } else if(service.compare("ir") == 0) { 105 | result = irInit(); 106 | cleanup = &irCleanup; 107 | } else if(service.compare("ac") == 0) { 108 | result = acInit(); 109 | cleanup = &acExit; 110 | } else if(service.compare("ptm") == 0) { 111 | result = ptmInit(); 112 | cleanup = &ptmExit; 113 | } else if(service.compare("kernel") == 0) { 114 | result = khaxInit(); 115 | cleanup = &khaxExit; 116 | } else { 117 | if(!platformIsNinjhax() || (service.compare("csnd") == 0 && !serviceCheckNew3DS()) || serviceRequire("kernel")) { 118 | if(service.compare("am") == 0) { 119 | result = amInit(); 120 | cleanup = &amExit; 121 | } else if(service.compare("csnd") == 0) { 122 | result = csndInit(); 123 | cleanup = &csndExit; 124 | } else if(service.compare("nor") == 0) { 125 | result = CFGNOR_Initialize(1); 126 | cleanup = &CFGNOR_Shutdown; 127 | } 128 | } else { 129 | return false; 130 | } 131 | } 132 | 133 | if(result == 0) { 134 | services[service] = cleanup; 135 | } else { 136 | platformSetError(serviceParseError((u32) result)); 137 | } 138 | 139 | return result == 0; 140 | } 141 | 142 | Error serviceParseError(u32 error) { 143 | Error err; 144 | 145 | err.raw = error; 146 | err.module = (ErrorModule) GET_BITS(error, 10, 17); 147 | err.level = (ErrorLevel) GET_BITS(error, 27, 31); 148 | err.summary = (ErrorSummary) GET_BITS(error, 21, 26); 149 | err.description = (ErrorDescription) GET_BITS(error, 0, 9); 150 | 151 | return err; 152 | } -------------------------------------------------------------------------------- /tools/locate_homemenu.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import glob 4 | import struct 5 | 6 | code = ''; 7 | addrdb = {}; 8 | base = 0x00100000; 9 | 10 | def findNearestSTMFD(code, pos): 11 | pos = (pos // 4) * 4; 12 | term = pos - 0x1000; 13 | if term < 0: 14 | term = 0; 15 | while (pos >= term) : 16 | if (code[pos + 2: pos + 4] == '\x2d\xe9'): 17 | return pos; 18 | pos -= 4; 19 | return 0; 20 | 21 | def findFunction(code, sig): 22 | global base; 23 | 24 | t = code.find(sig); 25 | if (t == -1): 26 | return 0; 27 | return base + findNearestSTMFD(code, t); 28 | 29 | def save(k, v): 30 | global addrdb, base; 31 | if (not addrdb.has_key(k)): 32 | addrdb[k] = '0'; 33 | if (v != 0): 34 | addrdb[k] = hex(v); 35 | 36 | def findAll(code, sig): 37 | r = []; 38 | off = 0; 39 | while True: 40 | t = code.find(sig, off); 41 | if (t == -1): 42 | return r; 43 | off = t + 1; 44 | r.append(t); 45 | 46 | def parseHexStr(s): 47 | t = ''; 48 | for i in s.split(' '): 49 | if (len(i) > 0): 50 | t += chr(int('0x' + i, 0)); 51 | return t; 52 | 53 | def locateHid(): 54 | global code, base; 55 | 56 | save('hidObj', 0); 57 | t = code.find('hid:USER'); 58 | if (t == -1): 59 | print('strHidUser not found'); 60 | return; 61 | strHidUser = t + base; 62 | print('strHidUser: %08x' % strHidUser); 63 | 64 | t = code.find(struct.pack('I', strHidUser)); 65 | if (t == -1): 66 | print('refHidUser not found'); 67 | return; 68 | refHidUser = t + base; 69 | print('refHidUser: %08x' % refHidUser); 70 | 71 | r = findAll(code, struct.pack('I', refHidUser - 8)); 72 | hidObj = 0; 73 | for i in r: 74 | (t,) = struct.unpack('I', code[i + 4: i + 8]); 75 | if ((t & 0x80000000) == 0): 76 | hidObj = t; 77 | 78 | print('hidObj: %08x' % hidObj); 79 | 80 | save('hidObj', hidObj); 81 | 82 | def locateFS() : 83 | global code, base; 84 | save('fsUserHandle', 0); 85 | save('fsOpenFile', findFunction(code, parseHexStr('c2 01 02 08'))); 86 | save('fsOpenArchive', findFunction(code, parseHexStr('c2 00 0c 08'))); 87 | save('fsWriteFile', findFunction(code, parseHexStr('02 01 03 08'))); 88 | t = code.find(parseHexStr('f9 67 a0 08')); 89 | if (t == 0): 90 | return; 91 | (fsUserHandle,) = struct.unpack('I', code[t - 4: t]); 92 | save('fsUserHandle', fsUserHandle); 93 | 94 | 95 | 96 | 97 | 98 | with open(sys.argv[1], 'rb') as f: 99 | code = f.read(); 100 | 101 | 102 | save('mountRom', findFunction(code, parseHexStr('0C 00 9D E5 00 10 90 E5 28 10 91 E5 31 FF 2F E1 '))); 103 | save('mountRom', findFunction(code, '\x31\xFF\x2F\xE1\x04\x00\xA0\xE1\x0F\x10\xA0\xE1\xA4\x2F\xB0\xE1')); 104 | save('mountArchive', findFunction(code, '\x10\x00\x97\xE5\xD8\x20\xCD\xE1\x00\x00\x8D')); 105 | save('regArchive', findFunction(code, '\xB4\x44\x20\xC8\x59\x46\x60\xD8')); 106 | save('mountArchive', findFunction(code, '\x28\xD0\x4D\xE2\x00\x40\xA0\xE1\xA8\x60\x9F\xE5\x01\xC0\xA0\xE3')); 107 | save('getServiceHandle', findFunction(code, parseHexStr(' F8 67 A0 D8'))); 108 | save('userFsTryOpen', findFunction(code, parseHexStr('0D 10 A0 E1 00 C0 90 E5 04 00 A0 E1 3C FF 2F E1'))); 109 | save('userFsTryOpen', findFunction(code, parseHexStr('10 10 8D E2 00 C0 90 E5 05 00 A0 E1 3C FF 2F E1'))); 110 | save('nnInitCardUpd', findFunction(code, parseHexStr('42 00 07 00'))); 111 | save('aptStartApplet', findFunction(code, parseHexStr('40 01 15 00'))); 112 | save('gxFlushDCahce', findFunction(code, parseHexStr(' 06 30 A0 E1 04 20 A0 E1 05 10 A0 E1'))); 113 | save('fsReadFile', findFunction(code, parseHexStr(' C2 00 02 08'))); 114 | 115 | 116 | 117 | locateHid(); 118 | locateFS(); 119 | print(repr(addrdb)); 120 | 121 | for i in addrdb: 122 | if (addrdb[i] == '0'): 123 | print('***WARNING*** Failed locating symbol %s , some patches may not work.' % i); 124 | 125 | ptr = 0x00200000 - base; 126 | (t,) = struct.unpack('I', code[ptr: ptr+4]); 127 | 128 | print('if (t == 0x%08x ) {' % t); 129 | print('ntrConfig->HomeMenuVersion = SYSTEM_VERSION(INSERT_YOUR_VERSION_HERE);'); 130 | print('ntrConfig->HomeMenuInjectAddr = ' + addrdb['gxFlushDCahce'] + ';'); 131 | print('ntrConfig->HomeFSReadAddr = ' + addrdb['fsReadFile'] + ';'); 132 | print('ntrConfig->HomeCardUpdateInitAddr = ' + addrdb['nnInitCardUpd'] + ';'); 133 | print('ntrConfig->HomeFSUHandleAddr = ' + addrdb['fsUserHandle'] + ';'); 134 | print('ntrConfig->HomeAptStartAppletAddr = ' + addrdb['aptStartApplet'] + ';'); 135 | print('}'); 136 | 137 | 138 | -------------------------------------------------------------------------------- /lib/ctrcommon/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | include $(DEVKITARM)/base_rules 10 | 11 | #--------------------------------------------------------------------------------- 12 | # TARGET is the name of the output 13 | # BUILD is the directory where object files & intermediate files will be placed 14 | # SOURCES is a list of directories containing source code 15 | # DATA is a list of directories containing data files 16 | # INCLUDES is a list of directories containing header files 17 | #--------------------------------------------------------------------------------- 18 | TARGET := ctrcommon 19 | BUILD := build 20 | SOURCES := source \ 21 | source/ctrcommon \ 22 | source/libkhax \ 23 | source/servicepatch 24 | 25 | DATA := data 26 | INCLUDES := include \ 27 | ../libctru/include 28 | 29 | #--------------------------------------------------------------------------------- 30 | # options for code generation 31 | #--------------------------------------------------------------------------------- 32 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 33 | 34 | CFLAGS := -g -Wall -Wno-strict-aliasing -O3 -mword-relocations \ 35 | -fomit-frame-pointer -ffast-math \ 36 | $(ARCH) 37 | 38 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DLIBKHAX_AS_LIB 39 | 40 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 41 | 42 | CFLAGS += -std=gnu99 43 | 44 | ASFLAGS := -g $(ARCH) 45 | 46 | LIBS := -lctru -lm 47 | 48 | #--------------------------------------------------------------------------------- 49 | # list of directories containing libraries, this must be the top level containing 50 | # include and lib 51 | #--------------------------------------------------------------------------------- 52 | LIBDIRS := $(CTRULIB) 53 | 54 | #--------------------------------------------------------------------------------- 55 | # no real need to edit anything past this point unless you need to add additional 56 | # rules for different file extensions 57 | #--------------------------------------------------------------------------------- 58 | ifneq ($(BUILD),$(notdir $(CURDIR))) 59 | #--------------------------------------------------------------------------------- 60 | 61 | export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a 62 | 63 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 64 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 65 | 66 | export DEPSDIR := $(CURDIR)/$(BUILD) 67 | 68 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 69 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 70 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 71 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 72 | 73 | #--------------------------------------------------------------------------------- 74 | # use CXX for linking C++ projects, CC for standard C 75 | #--------------------------------------------------------------------------------- 76 | ifeq ($(strip $(CPPFILES)),) 77 | #--------------------------------------------------------------------------------- 78 | export LD := $(CC) 79 | #--------------------------------------------------------------------------------- 80 | else 81 | #--------------------------------------------------------------------------------- 82 | export LD := $(CXX) 83 | #--------------------------------------------------------------------------------- 84 | endif 85 | #--------------------------------------------------------------------------------- 86 | 87 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 88 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 89 | 90 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 91 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 92 | -I$(CURDIR)/$(BUILD) 93 | 94 | .PHONY: $(BUILD) clean all 95 | 96 | #--------------------------------------------------------------------------------- 97 | all: $(BUILD) 98 | 99 | dist-bin: all 100 | @tar -cjf ctrcommon.tar.bz2 include lib tools 101 | 102 | dist-src: 103 | @tar -cjf ctrcommon-src.tar.bz2 include source tools Makefile 104 | 105 | dist: dist-src dist-bin 106 | 107 | install: dist-bin 108 | mkdir -p $(DEVKITPRO)/ctrcommon 109 | bzip2 -cd ctrcommon.tar.bz2 | tar -x -C $(DEVKITPRO)/ctrcommon 110 | 111 | dox: 112 | @doxygen Doxyfile 113 | @doxygen Doxyfile.internal 114 | 115 | lib: 116 | @[ -d $@ ] || mkdir -p $@ 117 | 118 | $(BUILD): lib 119 | @[ -d $@ ] || mkdir -p $@ 120 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 121 | 122 | #--------------------------------------------------------------------------------- 123 | clean: 124 | @echo clean ... 125 | @rm -fr $(BUILD) lib docs internal_docs 126 | 127 | #--------------------------------------------------------------------------------- 128 | else 129 | 130 | DEPENDS := $(OFILES:.o=.d) 131 | 132 | BUILD: $(OUTPUT) 133 | 134 | #--------------------------------------------------------------------------------- 135 | # main targets 136 | #--------------------------------------------------------------------------------- 137 | $(OUTPUT) : $(OFILES) 138 | 139 | submodules: 140 | @git submodule init 141 | @git submodule update --recursive 142 | 143 | #--------------------------------------------------------------------------------- 144 | %.bin.o : %.bin 145 | #--------------------------------------------------------------------------------- 146 | @echo $(notdir $<) 147 | @$(bin2o) 148 | 149 | #--------------------------------------------------------------------------------- 150 | %.vsh.o : %.vsh 151 | #--------------------------------------------------------------------------------- 152 | @echo $(notdir $<) 153 | @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin 154 | @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ 155 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h 156 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h 157 | @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h 158 | @rm ../$(notdir $<).shbin 159 | 160 | -include $(DEPENDS) 161 | 162 | #--------------------------------------------------------------------------------------- 163 | endif 164 | #--------------------------------------------------------------------------------------- 165 | -------------------------------------------------------------------------------- /template-cia.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "$(APP_TITLE)" 3 | CompanyCode : "00" 4 | ProductCode : "$(APP_PRODUCT_CODE)" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | TitleInfo: 9 | UniqueId : $(APP_UNIQUE_ID) 10 | Category : Application 11 | 12 | CardInfo: 13 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 14 | MediaType : Card1 # Card1 / Card2 15 | CardDevice : None # NorFlash(Pick this if you use savedata) / None 16 | 17 | Option: 18 | UseOnSD : true # true if App is to be installed to SD 19 | FreeProductCode : true # Removes limitations on ProductCode 20 | MediaFootPadding : false # If true CCI files are created with padding 21 | EnableCrypt : false # Enables encryption for NCCH and CIA 22 | EnableCompress : true # Compresses exefs code 23 | 24 | #Rom: 25 | # Specifies the root path of the file system to include in the ROM. 26 | # HostRoot : "romfs" 27 | 28 | AccessControlInfo: 29 | # UseOtherVariationSaveData : true 30 | # UseExtSaveData : true 31 | # ExtSaveDataId: 0xffffffff 32 | # SystemSaveDataId1: 0x220 33 | # SystemSaveDataId2: 0x00040010 34 | # OtherUserSaveDataId1: 0x220 35 | # OtherUserSaveDataId2: 0x330 36 | # OtherUserSaveDataId3: 0x440 37 | # UseExtendedSaveDataAccessControl: true 38 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 39 | FileSystemAccess: 40 | # - CategorySystemApplication 41 | # - CategoryHardwareCheck 42 | - CategoryFileSystemTool 43 | - Debug 44 | # - TwlCardBackup 45 | # - TwlNandData 46 | # - Boss 47 | - DirectSdmc 48 | # - Core 49 | # - CtrNandRo 50 | # - CtrNandRw 51 | # - CtrNandRoWrite 52 | # - CategorySystemSettings 53 | # - CardBoard 54 | # - ExportImportIvs 55 | - DirectSdmcWrite 56 | # - SwitchCleanup 57 | # - SaveDataMove 58 | # - Shop 59 | # - Shell 60 | # - CategoryHomeMenu 61 | IoAccessControl: 62 | # - FsMountNand 63 | # - FsMountNandRoWrite 64 | # - FsMountTwln 65 | # - FsMountWnand 66 | # - FsMountCardSpi 67 | # - UseSdif3 68 | # - CreateSeed 69 | # - UseCardSpi 70 | 71 | IdealProcessor : 0 72 | AffinityMask : 1 73 | 74 | Priority : 16 75 | 76 | MaxCpu : 0x9E # Default 77 | 78 | DisableDebug : true 79 | EnableForceDebug : false 80 | CanWriteSharedPage : true 81 | CanUsePrivilegedPriority : false 82 | CanUseNonAlphabetAndNumber : true 83 | PermitMainFunctionArgument : true 84 | CanShareDeviceMemory : true 85 | RunnableOnSleep : false 86 | SpecialMemoryArrange : true 87 | 88 | CoreVersion : 2 89 | DescVersion : 2 90 | 91 | ReleaseKernelMajor : "02" 92 | ReleaseKernelMinor : "33" 93 | MemoryType : Application # Application / System / Base 94 | HandleTableSize: 512 95 | IORegisterMapping: 96 | - 1ff50000-1ff57fff 97 | - 1ff70000-1ff77fff 98 | MemoryMapping: 99 | - 1f000000-1f5fffff:r 100 | SystemCallAccess: 101 | ArbitrateAddress: 34 102 | Break: 60 103 | CancelTimer: 28 104 | ClearEvent: 25 105 | ClearTimer: 29 106 | CloseHandle: 35 107 | ConnectToPort: 45 108 | ControlMemory: 1 109 | CreateAddressArbiter: 33 110 | CreateEvent: 23 111 | CreateMemoryBlock: 30 112 | CreateMutex: 19 113 | CreateSemaphore: 21 114 | CreateThread: 8 115 | CreateTimer: 26 116 | DuplicateHandle: 39 117 | ExitProcess: 3 118 | ExitThread: 9 119 | GetCurrentProcessorNumber: 17 120 | GetHandleInfo: 41 121 | GetProcessId: 53 122 | GetProcessIdOfThread: 54 123 | GetProcessIdealProcessor: 6 124 | GetProcessInfo: 43 125 | GetResourceLimit: 56 126 | GetResourceLimitCurrentValues: 58 127 | GetResourceLimitLimitValues: 57 128 | GetSystemInfo: 42 129 | GetSystemTick: 40 130 | GetThreadContext: 59 131 | GetThreadId: 55 132 | GetThreadIdealProcessor: 15 133 | GetThreadInfo: 44 134 | GetThreadPriority: 11 135 | MapMemoryBlock: 31 136 | OutputDebugString: 61 137 | QueryMemory: 2 138 | ReleaseMutex: 20 139 | ReleaseSemaphore: 22 140 | SendSyncRequest1: 46 141 | SendSyncRequest2: 47 142 | SendSyncRequest3: 48 143 | SendSyncRequest4: 49 144 | SendSyncRequest: 50 145 | SetThreadPriority: 12 146 | SetTimer: 27 147 | SignalEvent: 24 148 | SleepThread: 10 149 | UnmapMemoryBlock: 32 150 | WaitSynchronization1: 36 151 | WaitSynchronizationN: 37 152 | Backdoor: 123 153 | controlProcessMemory: 112 154 | StartInterProcessDma: 85 155 | FlushProcessDataCache: 84 156 | InvalidateProcessDataCache: 82 157 | GetDmaState: 87 158 | OpenProcess: 51 159 | InterruptNumbers: 160 | ServiceAccessControl: 161 | - APT:U 162 | - $hioFIO 163 | - $hostio0 164 | - $hostio1 165 | - ac:u 166 | - boss:U 167 | - cam:u 168 | - cecd:u 169 | - cfg:u 170 | - dlp:FKCL 171 | - dlp:SRVR 172 | - dsp::DSP 173 | - frd:u 174 | - fs:USER 175 | - gsp::Gpu 176 | - hid:USER 177 | - http:C 178 | - ir:u 179 | - mic:u 180 | - ndm:u 181 | - news:u 182 | - nwm::UDS 183 | - ptm:u 184 | - pxi:dev 185 | - soc:U 186 | - ssl:C 187 | - y2r:u 188 | - am:u 189 | - cfg:nor 190 | - csnd:SND 191 | 192 | SystemControlInfo: 193 | SaveDataSize: 0KB # It doesn't use any save data. 194 | RemasterVersion: 2 195 | StackSize: 0x40000 196 | # JumpId: 0 197 | Dependency: 198 | ac: 0x0004013000002402L 199 | am: 0x0004013000001502L 200 | boss: 0x0004013000003402L 201 | camera: 0x0004013000001602L 202 | cecd: 0x0004013000002602L 203 | cfg: 0x0004013000001702L 204 | codec: 0x0004013000001802L 205 | csnd: 0x0004013000002702L 206 | dlp: 0x0004013000002802L 207 | dsp: 0x0004013000001a02L 208 | friends: 0x0004013000003202L 209 | gpio: 0x0004013000001b02L 210 | gsp: 0x0004013000001c02L 211 | hid: 0x0004013000001d02L 212 | http: 0x0004013000002902L 213 | i2c: 0x0004013000001e02L 214 | ir: 0x0004013000003302L 215 | mcu: 0x0004013000001f02L 216 | mic: 0x0004013000002002L 217 | ndm: 0x0004013000002b02L 218 | news: 0x0004013000003502L 219 | nim: 0x0004013000002c02L 220 | nwm: 0x0004013000002d02L 221 | pdn: 0x0004013000002102L 222 | ps: 0x0004013000003102L 223 | ptm: 0x0004013000002202L 224 | ro: 0x0004013000003702L 225 | socket: 0x0004013000002e02L 226 | spi: 0x0004013000002302L 227 | ssl: 0x0004013000002f02L 228 | -------------------------------------------------------------------------------- /template-cia-0.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "$(APP_TITLE)" 3 | CompanyCode : "00" 4 | ProductCode : "$(APP_PRODUCT_CODE)" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | TitleInfo: 9 | UniqueId : $(APP_UNIQUE_ID) 10 | Category : Application 11 | 12 | CardInfo: 13 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 14 | MediaType : Card1 # Card1 / Card2 15 | CardDevice : None # NorFlash(Pick this if you use savedata) / None 16 | 17 | Option: 18 | UseOnSD : true # true if App is to be installed to SD 19 | FreeProductCode : true # Removes limitations on ProductCode 20 | MediaFootPadding : false # If true CCI files are created with padding 21 | EnableCrypt : false # Enables encryption for NCCH and CIA 22 | EnableCompress : true # Compresses exefs code 23 | 24 | #Rom: 25 | # Specifies the root path of the file system to include in the ROM. 26 | # HostRoot : "romfs" 27 | 28 | AccessControlInfo: 29 | # UseOtherVariationSaveData : true 30 | # UseExtSaveData : true 31 | # ExtSaveDataId: 0xffffffff 32 | # SystemSaveDataId1: 0x220 33 | # SystemSaveDataId2: 0x00040010 34 | # OtherUserSaveDataId1: 0x220 35 | # OtherUserSaveDataId2: 0x330 36 | # OtherUserSaveDataId3: 0x440 37 | # UseExtendedSaveDataAccessControl: true 38 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 39 | FileSystemAccess: 40 | # - CategorySystemApplication 41 | # - CategoryHardwareCheck 42 | - CategoryFileSystemTool 43 | - Debug 44 | # - TwlCardBackup 45 | # - TwlNandData 46 | # - Boss 47 | - DirectSdmc 48 | # - Core 49 | # - CtrNandRo 50 | # - CtrNandRw 51 | # - CtrNandRoWrite 52 | # - CategorySystemSettings 53 | # - CardBoard 54 | # - ExportImportIvs 55 | - DirectSdmcWrite 56 | # - SwitchCleanup 57 | # - SaveDataMove 58 | # - Shop 59 | # - Shell 60 | # - CategoryHomeMenu 61 | IoAccessControl: 62 | # - FsMountNand 63 | # - FsMountNandRoWrite 64 | # - FsMountTwln 65 | # - FsMountWnand 66 | # - FsMountCardSpi 67 | # - UseSdif3 68 | # - CreateSeed 69 | # - UseCardSpi 70 | 71 | IdealProcessor : 0 72 | AffinityMask : 1 73 | 74 | Priority : 16 75 | 76 | MaxCpu : 0x9E # Default 77 | 78 | DisableDebug : true 79 | EnableForceDebug : false 80 | CanWriteSharedPage : true 81 | CanUsePrivilegedPriority : false 82 | CanUseNonAlphabetAndNumber : true 83 | PermitMainFunctionArgument : true 84 | CanShareDeviceMemory : true 85 | RunnableOnSleep : false 86 | SpecialMemoryArrange : true 87 | 88 | CoreVersion : 2 89 | DescVersion : 2 90 | 91 | ReleaseKernelMajor : "02" 92 | ReleaseKernelMinor : "33" 93 | MemoryType : Application # Application / System / Base 94 | HandleTableSize: 512 95 | IORegisterMapping: 96 | - 1ff50000-1ff57fff 97 | - 1ff70000-1ff77fff 98 | MemoryMapping: 99 | - 1f000000-1f5fffff:r 100 | SystemCallAccess: 101 | ArbitrateAddress: 34 102 | Break: 60 103 | CancelTimer: 28 104 | ClearEvent: 25 105 | ClearTimer: 29 106 | CloseHandle: 35 107 | ConnectToPort: 45 108 | ControlMemory: 1 109 | CreateAddressArbiter: 33 110 | CreateEvent: 23 111 | CreateMemoryBlock: 30 112 | CreateMutex: 19 113 | CreateSemaphore: 21 114 | CreateThread: 8 115 | CreateTimer: 26 116 | DuplicateHandle: 39 117 | ExitProcess: 3 118 | ExitThread: 9 119 | GetCurrentProcessorNumber: 17 120 | GetHandleInfo: 41 121 | GetProcessId: 53 122 | GetProcessIdOfThread: 54 123 | GetProcessIdealProcessor: 6 124 | GetProcessInfo: 43 125 | GetResourceLimit: 56 126 | GetResourceLimitCurrentValues: 58 127 | GetResourceLimitLimitValues: 57 128 | GetSystemInfo: 42 129 | GetSystemTick: 40 130 | GetThreadContext: 59 131 | GetThreadId: 55 132 | GetThreadIdealProcessor: 15 133 | GetThreadInfo: 44 134 | GetThreadPriority: 11 135 | MapMemoryBlock: 31 136 | OutputDebugString: 61 137 | QueryMemory: 2 138 | ReleaseMutex: 20 139 | ReleaseSemaphore: 22 140 | SendSyncRequest1: 46 141 | SendSyncRequest2: 47 142 | SendSyncRequest3: 48 143 | SendSyncRequest4: 49 144 | SendSyncRequest: 50 145 | SetThreadPriority: 12 146 | SetTimer: 27 147 | SignalEvent: 24 148 | SleepThread: 10 149 | UnmapMemoryBlock: 32 150 | WaitSynchronization1: 36 151 | WaitSynchronizationN: 37 152 | Backdoor: 123 153 | controlProcessMemory: 112 154 | StartInterProcessDma: 85 155 | FlushProcessDataCache: 84 156 | InvalidateProcessDataCache: 82 157 | GetDmaState: 87 158 | OpenProcess: 51 159 | InterruptNumbers: 160 | ServiceAccessControl: 161 | - APT:U 162 | - $hioFIO 163 | - $hostio0 164 | - $hostio1 165 | - ac:u 166 | - boss:U 167 | - cam:u 168 | - cecd:u 169 | - cfg:u 170 | - dlp:FKCL 171 | - dlp:SRVR 172 | - dsp::DSP 173 | - frd:u 174 | - fs:USER 175 | - gsp::Gpu 176 | - hid:USER 177 | - http:C 178 | - ir:u 179 | - mic:u 180 | - ndm:u 181 | - news:u 182 | - nwm::UDS 183 | - ptm:u 184 | - pxi:dev 185 | - soc:U 186 | - ssl:C 187 | - y2r:u 188 | - am:u 189 | - cfg:nor 190 | - csnd:SND 191 | 192 | SystemControlInfo: 193 | SaveDataSize: 0KB # It doesn't use any save data. 194 | RemasterVersion: 2 195 | StackSize: 0x40000 196 | # JumpId: 0 197 | Dependency: 198 | ac: 0x0004013000002402L 199 | am: 0x0004013000001502L 200 | boss: 0x0004013000003402L 201 | camera: 0x0004013000001602L 202 | cecd: 0x0004013000002602L 203 | cfg: 0x0004013000001702L 204 | codec: 0x0004013000001802L 205 | csnd: 0x0004013000002702L 206 | dlp: 0x0004013000002802L 207 | dsp: 0x0004013000001a02L 208 | friends: 0x0004013000003202L 209 | gpio: 0x0004013000001b02L 210 | gsp: 0x0004013000001c02L 211 | hid: 0x0004013000001d02L 212 | http: 0x0004013000002902L 213 | i2c: 0x0004013000001e02L 214 | ir: 0x0004013000003302L 215 | mcu: 0x0004013000001f02L 216 | mic: 0x0004013000002002L 217 | ndm: 0x0004013000002b02L 218 | news: 0x0004013000003502L 219 | nim: 0x0004013000002c02L 220 | nwm: 0x0004013000002d02L 221 | pdn: 0x0004013000002102L 222 | ps: 0x0004013000003102L 223 | ptm: 0x0004013000002202L 224 | ro: 0x0004013000003702L 225 | socket: 0x0004013000002e02L 226 | spi: 0x0004013000002302L 227 | ssl: 0x0004013000002f02L 228 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/platform.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_PLATFORM_HPP__ 2 | #define __CTRCOMMON_PLATFORM_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | #include 7 | 8 | typedef enum { 9 | MODULE_COMMON = 0, 10 | MODULE_NN_KERNEL = 1, 11 | MODULE_NN_UTIL = 2, 12 | MODULE_NN_FILE_SERVER = 3, 13 | MODULE_NN_LOADER_SERVER = 4, 14 | MODULE_NN_TCB = 5, 15 | MODULE_NN_OS = 6, 16 | MODULE_NN_DBG = 7, 17 | MODULE_NN_DMNT = 8, 18 | MODULE_NN_PDN = 9, 19 | MODULE_NN_GX = 10, 20 | MODULE_NN_I2C = 11, 21 | MODULE_NN_GPIO = 12, 22 | MODULE_NN_DD = 13, 23 | MODULE_NN_CODEC = 14, 24 | MODULE_NN_SPI = 15, 25 | MODULE_NN_PXI = 16, 26 | MODULE_NN_FS = 17, 27 | MODULE_NN_DI = 18, 28 | MODULE_NN_HID = 19, 29 | MODULE_NN_CAMERA = 20, 30 | MODULE_NN_PI = 21, 31 | MODULE_NN_PM = 22, 32 | MODULE_NN_PMLOW = 23, 33 | MODULE_NN_FSI = 24, 34 | MODULE_NN_SRV = 25, 35 | MODULE_NN_NDM = 26, 36 | MODULE_NN_NWM = 27, 37 | MODULE_NN_SOCKET = 28, 38 | MODULE_NN_LDR = 29, 39 | MODULE_NN_ACC = 30, 40 | MODULE_NN_ROMFS = 31, 41 | MODULE_NN_AM = 32, 42 | MODULE_NN_HIO = 33, 43 | MODULE_NN_UPDATER = 34, 44 | MODULE_NN_MIC = 35, 45 | MODULE_NN_FND = 36, 46 | MODULE_NN_MP = 37, 47 | MODULE_NN_MPWL = 38, 48 | MODULE_NN_AC = 39, 49 | MODULE_NN_HTTP = 40, 50 | MODULE_NN_DSP = 41, 51 | MODULE_NN_SND = 42, 52 | MODULE_NN_DLP = 43, 53 | MODULE_NN_HIOLOW = 44, 54 | MODULE_NN_CSND = 45, 55 | MODULE_NN_SSL = 46, 56 | MODULE_NN_AMLOW = 47, 57 | MODULE_NN_NEX = 48, 58 | MODULE_NN_FRIENDS = 49, 59 | MODULE_NN_RDT = 50, 60 | MODULE_NN_APPLET = 51, 61 | MODULE_NN_NIM = 52, 62 | MODULE_NN_PTM = 53, 63 | MODULE_NN_MIDI = 54, 64 | MODULE_NN_MC = 55, 65 | MODULE_NN_SWC = 56, 66 | MODULE_NN_FATFS = 57, 67 | MODULE_NN_NGC = 58, 68 | MODULE_NN_CARD = 59, 69 | MODULE_NN_CARDNOR = 60, 70 | MODULE_NN_SDMC = 61, 71 | MODULE_NN_BOSS = 62, 72 | MODULE_NN_DBM = 63, 73 | MODULE_NN_CONFIG = 64, 74 | MODULE_NN_PS = 65, 75 | MODULE_NN_CEC = 66, 76 | MODULE_NN_IR = 67, 77 | MODULE_NN_UDS = 68, 78 | MODULE_NN_PL = 69, 79 | MODULE_NN_CUP = 70, 80 | MODULE_NN_GYROSCOPE = 71, 81 | MODULE_NN_MCU = 72, 82 | MODULE_NN_NS = 73, 83 | MODULE_NN_NEWS = 74, 84 | MODULE_NN_RO = 75, 85 | MODULE_NN_GD = 76, 86 | MODULE_NN_CARDSPI = 77, 87 | MODULE_NN_EC = 78, 88 | MODULE_NN_WEBBRS = 79, 89 | MODULE_NN_TEST = 80, 90 | MODULE_NN_ENC = 81, 91 | MODULE_NN_PIA = 82, 92 | MODULE_NN_MVD = 92, // TODO: Check 93 | MODULE_NN_QTM = 96, // TODO: Check 94 | MODULE_APPLICATION = 254, 95 | MODULE_INVALID_RESULT_VALUE = 255 96 | } ErrorModule; 97 | 98 | typedef enum { 99 | LEVEL_SUCCESS = 0, 100 | LEVEL_INFO = 1, 101 | LEVEL_STATUS = 25, 102 | LEVEL_TEMPORARY = 26, 103 | LEVEL_PERMANENT = 27, 104 | LEVEL_USAGE = 28, 105 | LEVEL_REINIT = 29, 106 | LEVEL_RESET = 30, 107 | LEVEL_FATAL = 31 108 | } ErrorLevel; 109 | 110 | typedef enum { 111 | SUMMARY_SUCCESS = 0, 112 | SUMMARY_NOTHING_HAPPENED = 1, 113 | SUMMARY_WOULD_BLOCK = 2, 114 | SUMMARY_OUT_OF_RESOURCE = 3, 115 | SUMMARY_NOT_FOUND = 4, 116 | SUMMARY_INVALID_STATE = 5, 117 | SUMMARY_NOT_SUPPORTED = 6, 118 | SUMMARY_INVALID_ARGUMENT = 7, 119 | SUMMARY_WRONG_ARGUMENT = 8, 120 | SUMMARY_CANCELED = 9, 121 | SUMMARY_STATUS_CHANGED = 10, 122 | SUMMARY_INTERNAL = 11, 123 | SUMMARY_INVALID_RESULT_VALUE = 63 124 | } ErrorSummary; 125 | 126 | typedef enum { 127 | DESCRIPTION_SUCCESS = 0, 128 | // TODO: Check from here... 129 | DESCRIPTION_INVALID_MEMORY_PERMISSIONS = 2, 130 | DESCRIPTION_INVALID_TICKET_VERSION = 4, 131 | DESCRIPTION_STRING_TOO_BIG = 5, 132 | DESCRIPTION_ACCESS_DENIED = 6, 133 | DESCRIPTION_STRING_TOO_SMALL = 7, 134 | DESCRIPTION_CAMERA_BUSY = 8, 135 | DESCRIPTION_NOT_ENOUGH_MEMORY = 10, 136 | DESCRIPTION_SESSION_CLOSED_BY_REMOTE = 26, 137 | DESCRIPTION_INVALID_NCCH = 37, 138 | DESCRIPTION_INVALID_TITLE_VERSION = 39, 139 | DESCRIPTION_DATABASE_DOES_NOT_EXIST = 43, 140 | DESCRIPTION_TRIED_TO_UNINSTALL_SYSTEM_APP = 44, 141 | DESCRIPTION_ARCHIVE_NOT_MOUNTED = 101, 142 | DESCRIPTION_REQUEST_TIMED_OUT = 105, 143 | DESCRIPTION_INVALID_SIGNATURE = 106, 144 | DESCRIPTION_TITLE_NOT_FOUND = 120, 145 | DESCRIPTION_GAMECARD_NOT_INSERTED = 141, 146 | DESCRIPTION_INVALID_FILE_OPEN_FLAGS = 230, 147 | DESCRIPTION_INVALID_CONFIGURATION = 271, 148 | DESCRIPTION_NCCH_HASH_CHECK_FAILED = 391, 149 | DESCRIPTION_AES_VERIFICATION_FAILED = 392, 150 | DESCRIPTION_INVALID_DATABASE = 393, 151 | DESCRIPTION_SAVE_HASH_CHECK_FAILED = 395, 152 | DESCRIPTION_COMMAND_PERMISSION_DENIED = 630, 153 | DESCRIPTION_INVALID_PATH = 702, 154 | DESCRIPTION_INCORRECT_READ_SIZE = 761, 155 | // TODO: ...to here. 156 | DESCRIPTION_INVALID_SELECTION = 1000, 157 | DESCRIPTION_TOO_LARGE = 1001, 158 | DESCRIPTION_NOT_AUTHORIZED = 1002, 159 | DESCRIPTION_ALREADY_DONE = 1003, 160 | DESCRIPTION_INVALID_SIZE = 1004, 161 | DESCRIPTION_INVALID_ENUM_VALUE = 1005, 162 | DESCRIPTION_INVALID_COMBINATION = 1006, 163 | DESCRIPTION_NO_DATA = 1007, 164 | DESCRIPTION_BUSY = 1008, 165 | DESCRIPTION_MISALIGNED_ADDRESS = 1009, 166 | DESCRIPTION_MISALIGNED_SIZE = 1010, 167 | DESCRIPTION_OUT_OF_MEMORY = 1011, 168 | DESCRIPTION_NOT_IMPLEMENTED = 1012, 169 | DESCRIPTION_INVALID_ADDRESS = 1013, 170 | DESCRIPTION_INVALID_POINTER = 1014, 171 | DESCRIPTION_INVALID_HANDLE = 1015, 172 | DESCRIPTION_NOT_INITIALIZED = 1016, 173 | DESCRIPTION_ALREADY_INITIALIZED = 1017, 174 | DESCRIPTION_NOT_FOUND = 1018, 175 | DESCRIPTION_CANCEL_REQUESTED = 1019, 176 | DESCRIPTION_ALREADY_EXISTS = 1020, 177 | DESCRIPTION_OUT_OF_RANGE = 1021, 178 | DESCRIPTION_TIMEOUT = 1022, 179 | DESCRIPTION_INVALID_RESULT_VALUE = 1023 180 | } ErrorDescription; 181 | 182 | typedef struct { 183 | u32 raw; 184 | ErrorModule module; 185 | ErrorLevel level; 186 | ErrorSummary summary; 187 | ErrorDescription description; 188 | } Error; 189 | 190 | bool platformInit(); 191 | void platformCleanup(); 192 | 193 | bool platformIsRunning(); 194 | bool platformIsNinjhax(); 195 | 196 | bool platformExecuteKernel(s32 (*func)()); 197 | 198 | u32 platformGetDeviceId(); 199 | 200 | bool platformIsWifiConnected(); 201 | bool platformWaitForInternet(); 202 | u8 platformGetWifiLevel(); 203 | 204 | bool platformIsBatteryCharging(); 205 | u8 platformGetBatteryLevel(); 206 | 207 | u64 platformGetTime(); 208 | void platformDelay(int ms); 209 | 210 | void platformPrintf(const char* format, ...); 211 | 212 | bool platformHasError(); 213 | Error platformGetError(); 214 | void platformSetError(Error error); 215 | std::string platformGetErrorString(Error error); 216 | 217 | #endif -------------------------------------------------------------------------------- /template-cia-3.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "$(APP_TITLE)" 3 | CompanyCode : "00" 4 | ProductCode : "$(APP_PRODUCT_CODE)" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | TitleInfo: 9 | UniqueId : $(APP_UNIQUE_ID) 10 | Category : Application 11 | 12 | CardInfo: 13 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 14 | MediaType : Card1 # Card1 / Card2 15 | CardDevice : None # NorFlash(Pick this if you use savedata) / None 16 | 17 | Option: 18 | UseOnSD : true # true if App is to be installed to SD 19 | FreeProductCode : true # Removes limitations on ProductCode 20 | MediaFootPadding : false # If true CCI files are created with padding 21 | EnableCrypt : false # Enables encryption for NCCH and CIA 22 | EnableCompress : true # Compresses exefs code 23 | 24 | #Rom: 25 | # Specifies the root path of the file system to include in the ROM. 26 | # HostRoot : "romfs" 27 | 28 | AccessControlInfo: 29 | # UseOtherVariationSaveData : true 30 | # UseExtSaveData : true 31 | # ExtSaveDataId: 0xffffffff 32 | # SystemSaveDataId1: 0x220 33 | # SystemSaveDataId2: 0x00040010 34 | # OtherUserSaveDataId1: 0x220 35 | # OtherUserSaveDataId2: 0x330 36 | # OtherUserSaveDataId3: 0x440 37 | # UseExtendedSaveDataAccessControl: true 38 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 39 | FileSystemAccess: 40 | # - CategorySystemApplication 41 | # - CategoryHardwareCheck 42 | - CategoryFileSystemTool 43 | - Debug 44 | # - TwlCardBackup 45 | # - TwlNandData 46 | # - Boss 47 | - DirectSdmc 48 | # - Core 49 | # - CtrNandRo 50 | # - CtrNandRw 51 | # - CtrNandRoWrite 52 | # - CategorySystemSettings 53 | # - CardBoard 54 | # - ExportImportIvs 55 | - DirectSdmcWrite 56 | # - SwitchCleanup 57 | # - SaveDataMove 58 | # - Shop 59 | # - Shell 60 | # - CategoryHomeMenu 61 | IoAccessControl: 62 | # - FsMountNand 63 | # - FsMountNandRoWrite 64 | # - FsMountTwln 65 | # - FsMountWnand 66 | # - FsMountCardSpi 67 | # - UseSdif3 68 | # - CreateSeed 69 | # - UseCardSpi 70 | 71 | SystemMode: 80MB 72 | IdealProcessor : 0 73 | AffinityMask : 1 74 | 75 | Priority : 16 76 | 77 | MaxCpu : 0x9E # Default 78 | 79 | DisableDebug : true 80 | EnableForceDebug : false 81 | CanWriteSharedPage : true 82 | CanUsePrivilegedPriority : false 83 | CanUseNonAlphabetAndNumber : true 84 | PermitMainFunctionArgument : true 85 | CanShareDeviceMemory : true 86 | RunnableOnSleep : false 87 | SpecialMemoryArrange : true 88 | 89 | CoreVersion : 2 90 | DescVersion : 2 91 | 92 | ReleaseKernelMajor : "02" 93 | ReleaseKernelMinor : "33" 94 | MemoryType : Application # Application / System / Base 95 | HandleTableSize: 512 96 | IORegisterMapping: 97 | - 1ff50000-1ff57fff 98 | - 1ff70000-1ff77fff 99 | MemoryMapping: 100 | - 1f000000-1f5fffff:r 101 | SystemCallAccess: 102 | ArbitrateAddress: 34 103 | Break: 60 104 | CancelTimer: 28 105 | ClearEvent: 25 106 | ClearTimer: 29 107 | CloseHandle: 35 108 | ConnectToPort: 45 109 | ControlMemory: 1 110 | CreateAddressArbiter: 33 111 | CreateEvent: 23 112 | CreateMemoryBlock: 30 113 | CreateMutex: 19 114 | CreateSemaphore: 21 115 | CreateThread: 8 116 | CreateTimer: 26 117 | DuplicateHandle: 39 118 | ExitProcess: 3 119 | ExitThread: 9 120 | GetCurrentProcessorNumber: 17 121 | GetHandleInfo: 41 122 | GetProcessId: 53 123 | GetProcessIdOfThread: 54 124 | GetProcessIdealProcessor: 6 125 | GetProcessInfo: 43 126 | GetResourceLimit: 56 127 | GetResourceLimitCurrentValues: 58 128 | GetResourceLimitLimitValues: 57 129 | GetSystemInfo: 42 130 | GetSystemTick: 40 131 | GetThreadContext: 59 132 | GetThreadId: 55 133 | GetThreadIdealProcessor: 15 134 | GetThreadInfo: 44 135 | GetThreadPriority: 11 136 | MapMemoryBlock: 31 137 | OutputDebugString: 61 138 | QueryMemory: 2 139 | ReleaseMutex: 20 140 | ReleaseSemaphore: 22 141 | SendSyncRequest1: 46 142 | SendSyncRequest2: 47 143 | SendSyncRequest3: 48 144 | SendSyncRequest4: 49 145 | SendSyncRequest: 50 146 | SetThreadPriority: 12 147 | SetTimer: 27 148 | SignalEvent: 24 149 | SleepThread: 10 150 | UnmapMemoryBlock: 32 151 | WaitSynchronization1: 36 152 | WaitSynchronizationN: 37 153 | Backdoor: 123 154 | controlProcessMemory: 112 155 | StartInterProcessDma: 85 156 | FlushProcessDataCache: 84 157 | InvalidateProcessDataCache: 82 158 | GetDmaState: 87 159 | OpenProcess: 51 160 | InterruptNumbers: 161 | ServiceAccessControl: 162 | - APT:U 163 | - $hioFIO 164 | - $hostio0 165 | - $hostio1 166 | - ac:u 167 | - boss:U 168 | - cam:u 169 | - cecd:u 170 | - cfg:u 171 | - dlp:FKCL 172 | - dlp:SRVR 173 | - dsp::DSP 174 | - frd:u 175 | - fs:USER 176 | - gsp::Gpu 177 | - hid:USER 178 | - http:C 179 | - ir:u 180 | - mic:u 181 | - ndm:u 182 | - news:u 183 | - nwm::UDS 184 | - ptm:u 185 | - pxi:dev 186 | - soc:U 187 | - ssl:C 188 | - y2r:u 189 | - am:u 190 | - cfg:nor 191 | - csnd:SND 192 | 193 | SystemControlInfo: 194 | SaveDataSize: 0KB # It doesn't use any save data. 195 | RemasterVersion: 2 196 | StackSize: 0x40000 197 | # JumpId: 0 198 | Dependency: 199 | ac: 0x0004013000002402L 200 | am: 0x0004013000001502L 201 | boss: 0x0004013000003402L 202 | camera: 0x0004013000001602L 203 | cecd: 0x0004013000002602L 204 | cfg: 0x0004013000001702L 205 | codec: 0x0004013000001802L 206 | csnd: 0x0004013000002702L 207 | dlp: 0x0004013000002802L 208 | dsp: 0x0004013000001a02L 209 | friends: 0x0004013000003202L 210 | gpio: 0x0004013000001b02L 211 | gsp: 0x0004013000001c02L 212 | hid: 0x0004013000001d02L 213 | http: 0x0004013000002902L 214 | i2c: 0x0004013000001e02L 215 | ir: 0x0004013000003302L 216 | mcu: 0x0004013000001f02L 217 | mic: 0x0004013000002002L 218 | ndm: 0x0004013000002b02L 219 | news: 0x0004013000003502L 220 | nim: 0x0004013000002c02L 221 | nwm: 0x0004013000002d02L 222 | pdn: 0x0004013000002102L 223 | ps: 0x0004013000003102L 224 | ptm: 0x0004013000002202L 225 | ro: 0x0004013000003702L 226 | socket: 0x0004013000002e02L 227 | spi: 0x0004013000002302L 228 | ssl: 0x0004013000002f02L 229 | -------------------------------------------------------------------------------- /lib/ctrcommon/tools/template-cia.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "$(APP_TITLE)" 3 | CompanyCode : "00" 4 | ProductCode : "$(APP_PRODUCT_CODE)" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | TitleInfo: 9 | UniqueId : $(APP_UNIQUE_ID) 10 | Category : Application 11 | 12 | CardInfo: 13 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 14 | MediaType : Card1 # Card1 / Card2 15 | CardDevice : None # NorFlash(Pick this if you use savedata) / None 16 | 17 | Option: 18 | UseOnSD : true # true if App is to be installed to SD 19 | FreeProductCode : true # Removes limitations on ProductCode 20 | MediaFootPadding : false # If true CCI files are created with padding 21 | EnableCrypt : false # Enables encryption for NCCH and CIA 22 | EnableCompress : true # Compresses exefs code 23 | 24 | ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names 25 | ReadOnly: 26 | - .rodata 27 | - RO 28 | ReadWrite: 29 | - .data 30 | - RO 31 | Text: 32 | - .init 33 | - .text 34 | - STUP_ENTRY 35 | 36 | PlainRegion: # only used with SDK ELFs 37 | #- .module_id 38 | 39 | #Rom: 40 | # Specifies the root path of the file system to include in the ROM. 41 | # HostRoot : "romfs" 42 | 43 | AccessControlInfo: 44 | # UseOtherVariationSaveData : true 45 | # UseExtSaveData : true 46 | # ExtSaveDataId: 0xffffffff 47 | # SystemSaveDataId1: 0x220 48 | # SystemSaveDataId2: 0x00040010 49 | # OtherUserSaveDataId1: 0x220 50 | # OtherUserSaveDataId2: 0x330 51 | # OtherUserSaveDataId3: 0x440 52 | # UseExtendedSaveDataAccessControl: true 53 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 54 | FileSystemAccess: 55 | # - CategorySystemApplication 56 | # - CategoryHardwareCheck 57 | - CategoryFileSystemTool 58 | - Debug 59 | # - TwlCardBackup 60 | # - TwlNandData 61 | # - Boss 62 | - DirectSdmc 63 | # - Core 64 | # - CtrNandRo 65 | # - CtrNandRw 66 | # - CtrNandRoWrite 67 | # - CategorySystemSettings 68 | # - CardBoard 69 | # - ExportImportIvs 70 | - DirectSdmcWrite 71 | # - SwitchCleanup 72 | # - SaveDataMove 73 | # - Shop 74 | # - Shell 75 | # - CategoryHomeMenu 76 | IoAccessControl: 77 | # - FsMountNand 78 | # - FsMountNandRoWrite 79 | # - FsMountTwln 80 | # - FsMountWnand 81 | # - FsMountCardSpi 82 | # - UseSdif3 83 | # - CreateSeed 84 | # - UseCardSpi 85 | 86 | IdealProcessor : 0 87 | AffinityMask : 1 88 | 89 | Priority : 16 90 | 91 | MaxCpu : 0x9E # Default 92 | 93 | DisableDebug : true 94 | EnableForceDebug : false 95 | CanWriteSharedPage : true 96 | CanUsePrivilegedPriority : false 97 | CanUseNonAlphabetAndNumber : true 98 | PermitMainFunctionArgument : true 99 | CanShareDeviceMemory : true 100 | RunnableOnSleep : false 101 | SpecialMemoryArrange : true 102 | 103 | CoreVersion : 2 104 | DescVersion : 2 105 | 106 | ReleaseKernelMajor : "02" 107 | ReleaseKernelMinor : "33" 108 | MemoryType : Application # Application / System / Base 109 | HandleTableSize: 512 110 | IORegisterMapping: 111 | - 1ff50000-1ff57fff 112 | - 1ff70000-1ff77fff 113 | MemoryMapping: 114 | - 1f000000-1f5fffff:r 115 | SystemCallAccess: 116 | ArbitrateAddress: 34 117 | Break: 60 118 | CancelTimer: 28 119 | ClearEvent: 25 120 | ClearTimer: 29 121 | CloseHandle: 35 122 | ConnectToPort: 45 123 | ControlMemory: 1 124 | CreateAddressArbiter: 33 125 | CreateEvent: 23 126 | CreateMemoryBlock: 30 127 | CreateMutex: 19 128 | CreateSemaphore: 21 129 | CreateThread: 8 130 | CreateTimer: 26 131 | DuplicateHandle: 39 132 | ExitProcess: 3 133 | ExitThread: 9 134 | GetCurrentProcessorNumber: 17 135 | GetHandleInfo: 41 136 | GetProcessId: 53 137 | GetProcessIdOfThread: 54 138 | GetProcessIdealProcessor: 6 139 | GetProcessInfo: 43 140 | GetResourceLimit: 56 141 | GetResourceLimitCurrentValues: 58 142 | GetResourceLimitLimitValues: 57 143 | GetSystemInfo: 42 144 | GetSystemTick: 40 145 | GetThreadContext: 59 146 | GetThreadId: 55 147 | GetThreadIdealProcessor: 15 148 | GetThreadInfo: 44 149 | GetThreadPriority: 11 150 | MapMemoryBlock: 31 151 | OutputDebugString: 61 152 | QueryMemory: 2 153 | ReleaseMutex: 20 154 | ReleaseSemaphore: 22 155 | SendSyncRequest1: 46 156 | SendSyncRequest2: 47 157 | SendSyncRequest3: 48 158 | SendSyncRequest4: 49 159 | SendSyncRequest: 50 160 | SetThreadPriority: 12 161 | SetTimer: 27 162 | SignalEvent: 24 163 | SleepThread: 10 164 | UnmapMemoryBlock: 32 165 | WaitSynchronization1: 36 166 | WaitSynchronizationN: 37 167 | InterruptNumbers: 168 | ServiceAccessControl: 169 | - APT:U 170 | - $hioFIO 171 | - $hostio0 172 | - $hostio1 173 | - ac:u 174 | - boss:U 175 | - cam:u 176 | - cecd:u 177 | - cfg:u 178 | - dlp:FKCL 179 | - dlp:SRVR 180 | - dsp::DSP 181 | - frd:u 182 | - fs:USER 183 | - gsp::Gpu 184 | - hid:USER 185 | - http:C 186 | - ir:u 187 | - mic:u 188 | - ndm:u 189 | - news:u 190 | - nwm::UDS 191 | - ptm:u 192 | - pxi:dev 193 | - soc:U 194 | - ssl:C 195 | - y2r:u 196 | - am:u 197 | - cfg:nor 198 | - csnd:SND 199 | 200 | SystemControlInfo: 201 | SaveDataSize: 0KB # It doesn't use any save data. 202 | RemasterVersion: 2 203 | StackSize: 0x40000 204 | # JumpId: 0 205 | Dependency: 206 | ac: 0x0004013000002402L 207 | am: 0x0004013000001502L 208 | boss: 0x0004013000003402L 209 | camera: 0x0004013000001602L 210 | cecd: 0x0004013000002602L 211 | cfg: 0x0004013000001702L 212 | codec: 0x0004013000001802L 213 | csnd: 0x0004013000002702L 214 | dlp: 0x0004013000002802L 215 | dsp: 0x0004013000001a02L 216 | friends: 0x0004013000003202L 217 | gpio: 0x0004013000001b02L 218 | gsp: 0x0004013000001c02L 219 | hid: 0x0004013000001d02L 220 | http: 0x0004013000002902L 221 | i2c: 0x0004013000001e02L 222 | ir: 0x0004013000003302L 223 | mcu: 0x0004013000001f02L 224 | mic: 0x0004013000002002L 225 | ndm: 0x0004013000002b02L 226 | news: 0x0004013000003502L 227 | nim: 0x0004013000002c02L 228 | nwm: 0x0004013000002d02L 229 | pdn: 0x0004013000002102L 230 | ps: 0x0004013000003102L 231 | ptm: 0x0004013000002202L 232 | ro: 0x0004013000003702L 233 | socket: 0x0004013000002e02L 234 | spi: 0x0004013000002302L 235 | ssl: 0x0004013000002f02L 236 | -------------------------------------------------------------------------------- /source/svc.s: -------------------------------------------------------------------------------- 1 | .arm 2 | 3 | .align 4 4 | 5 | .global getThreadCommandBuffer 6 | .type getThreadCommandBuffer, %function 7 | getThreadCommandBuffer: 8 | mrc p15, 0, r0, c13, c0, 3 9 | add r0, #0x80 10 | bx lr 11 | 12 | 13 | .global svc_controlMemory 14 | .type svc_controlMemory, %function 15 | svc_controlMemory: 16 | stmfd sp!, {r0, r4} 17 | ldr r0, [sp, #0x8] 18 | ldr r4, [sp, #0x8+0x4] 19 | svc 0x01 20 | ldr r2, [sp], #4 21 | str r1, [r2] 22 | ldr r4, [sp], #4 23 | bx lr 24 | 25 | .global svc_exitProcess 26 | .type svc_exitProcess, %function 27 | svc_exitProcess: 28 | svc 0x03 29 | bx lr 30 | 31 | .global svc_createThread 32 | .type svc_createThread, %function 33 | svc_createThread: 34 | stmfd sp!, {r0, r4} 35 | ldr r0, [sp, #0x8] 36 | ldr r4, [sp, #0x8+0x4] 37 | svc 0x08 38 | ldr r2, [sp], #4 39 | str r1, [r2] 40 | ldr r4, [sp], #4 41 | bx lr 42 | 43 | .global svc_exitThread 44 | .type svc_exitThread, %function 45 | svc_exitThread: 46 | svc 0x09 47 | bx lr 48 | 49 | .global svc_sleepThread 50 | .type svc_sleepThread, %function 51 | svc_sleepThread: 52 | svc 0x0A 53 | bx lr 54 | 55 | .global svc_createMutex 56 | .type svc_createMutex, %function 57 | svc_createMutex: 58 | str r0, [sp, #-4]! 59 | svc 0x13 60 | ldr r3, [sp], #4 61 | str r1, [r3] 62 | bx lr 63 | 64 | .global svc_releaseMutex 65 | .type svc_releaseMutex, %function 66 | svc_releaseMutex: 67 | svc 0x14 68 | bx lr 69 | 70 | .global svc_releaseSemaphore 71 | .type svc_releaseSemaphore, %function 72 | svc_releaseSemaphore: 73 | str r0, [sp,#-4]! 74 | svc 0x16 75 | ldr r2, [sp], #4 76 | str r1, [r2] 77 | bx lr 78 | 79 | .global svc_createEvent 80 | .type svc_createEvent, %function 81 | svc_createEvent: 82 | str r0, [sp,#-4]! 83 | svc 0x17 84 | ldr r2, [sp], #4 85 | str r1, [r2] 86 | bx lr 87 | 88 | .global svc_signalEvent 89 | .type svc_signalEvent, %function 90 | svc_signalEvent: 91 | svc 0x18 92 | bx lr 93 | 94 | .global svc_clearEvent 95 | .type svc_clearEvent, %function 96 | svc_clearEvent: 97 | svc 0x19 98 | bx lr 99 | 100 | .global svc_createMemoryBlock 101 | .type svc_createMemoryBlock, %function 102 | svc_createMemoryBlock: 103 | str r0, [sp, #-4]! 104 | ldr r0, [sp, #4] 105 | svc 0x1E 106 | ldr r2, [sp], #4 107 | str r1, [r2] 108 | bx lr 109 | 110 | .global svc_mapMemoryBlock 111 | .type svc_mapMemoryBlock, %function 112 | svc_mapMemoryBlock: 113 | svc 0x1F 114 | bx lr 115 | 116 | .global svc_unmapMemoryBlock 117 | .type svc_unmapMemoryBlock, %function 118 | svc_unmapMemoryBlock: 119 | svc 0x20 120 | bx lr 121 | 122 | .global svc_arbitrateAddress 123 | .type svc_arbitrateAddress, %function 124 | svc_arbitrateAddress: 125 | svc 0x22 126 | bx lr 127 | 128 | .global svc_closeHandle 129 | .type svc_closeHandle, %function 130 | svc_closeHandle: 131 | svc 0x23 132 | bx lr 133 | 134 | .global svc_waitSynchronization1 135 | .type svc_waitSynchronization1, %function 136 | svc_waitSynchronization1: 137 | svc 0x24 138 | bx lr 139 | 140 | .global svc_waitSynchronizationN 141 | .type svc_waitSynchronizationN, %function 142 | svc_waitSynchronizationN: 143 | str r5, [sp, #-4]! 144 | mov r5, r0 145 | ldr r0, [sp, #0x4] 146 | ldr r4, [sp, #0x4+0x4] 147 | svc 0x25 148 | str r1, [r5] 149 | ldr r5, [sp], #4 150 | bx lr 151 | 152 | .global svc_getSystemTick 153 | .type svc_getSystemTick, %function 154 | svc_getSystemTick: 155 | svc 0x28 156 | bx lr 157 | 158 | .global svc_getSystemInfo 159 | .type svc_getSystemInfo, %function 160 | svc_getSystemInfo: 161 | stmfd sp!, {r0, r4} 162 | svc 0x2A 163 | ldr r4, [sp], #4 164 | str r1, [r4] 165 | str r2, [r4, #4] 166 | # str r3, [r4, #8] # ? 167 | ldr r4, [sp], #4 168 | bx lr 169 | 170 | .global svc_getProcessInfo 171 | .type svc_getProcessInfo, %function 172 | svc_getProcessInfo: 173 | stmfd sp!, {r0, r4} 174 | svc 0x2B 175 | ldr r4, [sp], #4 176 | str r1, [r4] 177 | str r2, [r4, #4] 178 | ldr r4, [sp], #4 179 | bx lr 180 | 181 | .global svc_connectToPort 182 | .type svc_connectToPort, %function 183 | svc_connectToPort: 184 | str r0, [sp,#-0x4]! 185 | svc 0x2D 186 | ldr r3, [sp], #4 187 | str r1, [r3] 188 | bx lr 189 | 190 | .global svc_sendSyncRequest 191 | .type svc_sendSyncRequest, %function 192 | svc_sendSyncRequest: 193 | svc 0x32 194 | bx lr 195 | 196 | .global svc_getProcessId 197 | .type svc_getProcessId, %function 198 | svc_getProcessId: 199 | str r0, [sp,#-0x4]! 200 | svc 0x35 201 | ldr r3, [sp], #4 202 | str r1, [r3] 203 | bx lr 204 | 205 | .global svc_getThreadId 206 | .type svc_getThreadId, %function 207 | svc_getThreadId: 208 | str r0, [sp,#-0x4]! 209 | svc 0x37 210 | ldr r3, [sp], #4 211 | str r1, [r3] 212 | bx lr 213 | 214 | 215 | .global svc_setThreadIdealProcessor 216 | .type svc_setThreadIdealProcessor, %function 217 | svc_setThreadIdealProcessor: 218 | svc 0x10 219 | bx lr 220 | 221 | .global svc_openThread 222 | .type svc_openThread, %function 223 | svc_openThread: 224 | str r0, [sp,#-0x4]! 225 | svc 0x34 226 | ldr r3, [sp], #4 227 | str r1, [r3] 228 | bx lr 229 | 230 | .global svc_flushProcessDataCache 231 | .type svc_flushProcessDataCache, %function 232 | svc_flushProcessDataCache: 233 | svc 0x54 234 | bx lr 235 | 236 | .global svc_invalidateProcessDataCache 237 | .type svc_invalidateProcessDataCache, %function 238 | svc_invalidateProcessDataCache: 239 | svc 0x52 240 | bx lr 241 | 242 | .global svc_queryMemory 243 | .type svc_queryMemory, %function 244 | svc_queryMemory: 245 | svc 0x02 246 | bx lr 247 | 248 | .global svc_addCodeSegment 249 | .type svc_addCodeSegment, %function 250 | svc_addCodeSegment: 251 | svc 0x7a 252 | bx lr 253 | 254 | .global svc_openProcess 255 | .type svc_openProcess, %function 256 | svc_openProcess: 257 | str r0, [sp,#-0x4]! 258 | svc 0x33 259 | ldr r3, [sp], #4 260 | str r1, [r3] 261 | bx lr 262 | 263 | .global svc_controlProcessMemory 264 | .type svc_controlProcessMemory, %function 265 | svc_controlProcessMemory: 266 | 267 | stmfd sp!, {r0, r4, r5} 268 | ldr r4, [sp, #0xC+0x0] 269 | ldr r5, [sp, #0xC+0x4] 270 | svc 0x70 271 | ldmfd sp!, {r2, r4, r5} 272 | bx lr 273 | 274 | 275 | .global svc_mapProcessMemory 276 | .type svc_mapProcessMemory, %function 277 | svc_mapProcessMemory: 278 | 279 | svc 0x71 280 | bx lr 281 | 282 | .global svc_startInterProcessDma 283 | .type svc_startInterProcessDma, %function 284 | svc_startInterProcessDma: 285 | 286 | stmfd sp!, {r0, r4, r5} 287 | ldr r0, [sp, #0xC] 288 | ldr r4, [sp, #0xC+0x4] 289 | ldr r5, [sp, #0xC+0x8] 290 | svc 0x55 291 | ldmfd sp!, {r2, r4, r5} 292 | str r1, [r2] 293 | bx lr 294 | 295 | .global svc_getDmaState 296 | .type svc_getDmaState, %function 297 | svc_getDmaState: 298 | 299 | str r0, [sp,#-0x4]! 300 | svc 0x57 301 | ldr r3, [sp], #4 302 | str r1, [r3] 303 | bx lr 304 | 305 | 306 | .global svc_backDoor 307 | .type svc_backDoor, %function 308 | svc_backDoor: 309 | svc 0x7b 310 | bx lr 311 | 312 | 313 | .global svc_getProcessList 314 | .type svc_getProcessList, %function 315 | svc_getProcessList: 316 | str r0, [sp,#-0x4]! 317 | svc 0x65 318 | ldr r3, [sp], #4 319 | str r1, [r3] 320 | bx lr 321 | 322 | 323 | .global svc_getThreadList 324 | .type svc_getThreadList, %function 325 | svc_getThreadList: 326 | str r0, [sp,#-0x4]! 327 | svc 0x66 328 | ldr r3, [sp], #4 329 | str r1, [r3] 330 | bx lr 331 | 332 | .global svc_getThreadContext 333 | .type svc_getThreadContext, %function 334 | svc_getThreadContext: 335 | svc 0x3b 336 | bx lr 337 | 338 | 339 | 340 | .global svc_debugActiveProcess 341 | .type svc_debugActiveProcess, %function 342 | svc_debugActiveProcess: 343 | str r0, [sp,#-0x4]! 344 | svc 0x60 345 | ldr r3, [sp], #4 346 | str r1, [r3] 347 | bx lr 348 | 349 | .global svc_readProcessMemory 350 | .type svc_readProcessMemory, %function 351 | svc_readProcessMemory: 352 | svc 0x6a 353 | bx lr 354 | 355 | .global svc_writeProcessMemory 356 | .type svc_writeProcessMemory, %function 357 | svc_writeProcessMemory: 358 | svc 0x6b 359 | bx lr 360 | 361 | 362 | 363 | 364 | 365 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NO_CTRCOMMON := 1 2 | 3 | #--------------------------------------------------------------------------------- 4 | .SUFFIXES: 5 | #--------------------------------------------------------------------------------- 6 | 7 | 8 | 9 | ifeq ($(strip $(DEVKITPRO)),) 10 | $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") 11 | endif 12 | 13 | ifeq ($(strip $(DEVKITARM)),) 14 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 15 | endif 16 | 17 | CTRCOMMON = $(TOPDIR)/lib/ctrcommon 18 | 19 | TOPDIR ?= $(CURDIR) 20 | include $(DEVKITARM)/3ds_rules 21 | 22 | include $(TOPDIR)/resources/AppInfo 23 | 24 | APP_TITLE := $(shell echo "$(APP_TITLE)" | cut -c1-128) 25 | APP_DESCRIPTION := $(shell echo "$(APP_DESCRIPTION)" | cut -c1-256) 26 | APP_AUTHOR := $(shell echo "$(APP_AUTHOR)" | cut -c1-128) 27 | APP_PRODUCT_CODE := $(shell echo $(APP_PRODUCT_CODE) | cut -c1-16) 28 | APP_UNIQUE_ID := $(shell echo $(APP_UNIQUE_ID) | cut -c1-7) 29 | 30 | BUILD := build 31 | SOURCES := source 32 | DATA := data 33 | INCLUDES := $(SOURCES) include 34 | ICON := resources/icon.png 35 | 36 | #--------------------------------------------------------------------------------- 37 | # options for code generation 38 | #--------------------------------------------------------------------------------- 39 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 40 | 41 | COMMON_FLAGS := -g -Wall -Wno-strict-aliasing -O3 -mword-relocations -fomit-frame-pointer -ffast-math $(ARCH) $(INCLUDE) -DARM11 -D_3DS $(BUILD_FLAGS) 42 | 43 | CXXFLAGS := $(COMMON_FLAGS) -std=gnu++11 44 | ifeq ($(ENABLE_EXCEPTIONS),) 45 | CXXFLAGS += -fno-rtti -fno-exceptions 46 | endif 47 | 48 | CFLAGS := $(COMMON_FLAGS) -std=gnu99 49 | 50 | ASFLAGS := -g $(ARCH) 51 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 52 | 53 | LIBS := -lctru -lm 54 | LIBDIRS := $(PORTLIBS) $(CTRULIB) ./lib 55 | ifeq ($(NO_CTRCOMMON),) 56 | LIBS := -lctrcommon -lctru -lm 57 | LIBDIRS := $(CTRCOMMON) $(PORTLIBS) $(CTRULIB) ./lib 58 | endif 59 | 60 | RSF_3DS = $(CTRCOMMON)/tools/template-3ds.rsf 61 | RSF_CIA = ../template-cia.rsf 62 | 63 | ifeq ($(OS),Windows_NT) 64 | MAKEROM = $(CTRCOMMON)/tools/makerom.exe 65 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool.exe 66 | else 67 | UNAME_S := $(shell uname -s) 68 | ifeq ($(UNAME_S),Linux) 69 | MAKEROM = $(CTRCOMMON)/tools/makerom-linux 70 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool-linux 71 | endif 72 | ifeq ($(UNAME_S),Darwin) 73 | MAKEROM = $(CTRCOMMON)/tools/makerom-mac 74 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool-mac 75 | endif 76 | endif 77 | 78 | #--------------------------------------------------------------------------------- 79 | # no real need to edit anything past this point unless you need to add additional 80 | # rules for different file extensions 81 | #--------------------------------------------------------------------------------- 82 | ifneq ($(BUILD),$(notdir $(CURDIR))) 83 | #--------------------------------------------------------------------------------- 84 | 85 | recurse = $(shell find $2 -type $1 -name '$3' 2> /dev/null) 86 | 87 | null := 88 | SPACE := $(null) $(null) 89 | export OUTPUT_D := $(CURDIR)/output 90 | export OUTPUT_N := $(subst $(SPACE),,$(APP_TITLE)) 91 | export OUTPUT := $(OUTPUT_D)/$(OUTPUT_N) 92 | export TOPDIR := $(CURDIR) 93 | 94 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir) $(call recurse,d,$(CURDIR)/$(dir),*)) \ 95 | $(foreach dir,$(DATA),$(CURDIR)/$(dir) $(call recurse,d,$(CURDIR)/$(dir),*)) 96 | 97 | export DEPSDIR := $(CURDIR)/$(BUILD) 98 | 99 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.c))) 100 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.cpp))) 101 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.s))) 102 | BINFILES := $(foreach dir,$(DATA),$(notdir $(call recurse,f,$(dir),*.*))) 103 | 104 | #--------------------------------------------------------------------------------- 105 | # use CXX for linking C++ projects, CC for standard C 106 | #--------------------------------------------------------------------------------- 107 | ifeq ($(strip $(CPPFILES)),) 108 | #--------------------------------------------------------------------------------- 109 | export LD := $(CC) 110 | #--------------------------------------------------------------------------------- 111 | else 112 | #--------------------------------------------------------------------------------- 113 | export LD := $(CXX) 114 | #--------------------------------------------------------------------------------- 115 | endif 116 | #--------------------------------------------------------------------------------- 117 | 118 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 119 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 120 | 121 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 122 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 123 | -I$(CURDIR)/$(BUILD) 124 | 125 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 126 | 127 | export APP_ICON := $(TOPDIR)/$(ICON) 128 | 129 | .PHONY: $(BUILD) clean all 130 | 131 | #--------------------------------------------------------------------------------- 132 | all: $(BUILD) 133 | 134 | $(BUILD): 135 | @[ -d $@ ] || mkdir -p $@ 136 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 137 | 138 | #--------------------------------------------------------------------------------- 139 | clean: 140 | @echo clean ... 141 | @rm -fr $(BUILD) $(OUTPUT_D) 142 | 143 | 144 | #--------------------------------------------------------------------------------- 145 | else 146 | 147 | DEPENDS := $(OFILES:.o=.d) 148 | 149 | #--------------------------------------------------------------------------------- 150 | # main targets 151 | #--------------------------------------------------------------------------------- 152 | .PHONY: all 153 | all: $(OUTPUT).zip 154 | 155 | $(OUTPUT_D): 156 | @[ -d $@ ] || mkdir -p $@ 157 | 158 | icon.icn: $(TOPDIR)/resources/icon.png 159 | @$(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_TITLE)" -p "$(APP_AUTHOR)" -i $(TOPDIR)/resources/icon.png -o icon.icn > /dev/null 160 | 161 | $(OUTPUT).elf: $(OFILES) 162 | 163 | stripped.elf: $(OUTPUT).elf 164 | @cp $(OUTPUT).elf stripped.elf 165 | @$(PREFIX)strip stripped.elf 166 | 167 | 168 | $(OUTPUT).cia: stripped.elf icon.icn 169 | @$(MAKEROM) -f cia -o $(OUTPUT).cia -rsf $(RSF_CIA) -target t -exefslogo -elf stripped.elf -icon icon.icn -banner $(TOPDIR)/resources/banner.bin -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(APP_PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(APP_UNIQUE_ID)" 170 | @echo "built ... $(notdir $@)" 171 | 172 | $(OUTPUT).zip: $(OUTPUT_D) $(OUTPUT).elf $(OUTPUT).smdh $(OUTPUT).cia 173 | @cd $(OUTPUT_D); \ 174 | mkdir -p 3ds/$(OUTPUT_N); \ 175 | zip -r $(OUTPUT_N).zip $(OUTPUT_N).cia > /dev/null; \ 176 | rm -r 3ds 177 | @echo "built ... $(notdir $@)" 178 | 179 | #--------------------------------------------------------------------------------- 180 | # you need a rule like this for each extension you use as binary data 181 | #--------------------------------------------------------------------------------- 182 | %.bin.o : %.bin 183 | #--------------------------------------------------------------------------------- 184 | @echo $(notdir $<) 185 | @$(bin2o) 186 | 187 | # WARNING: This is not the right way to do this! TODO: Do it right! 188 | #--------------------------------------------------------------------------------- 189 | %.vsh.o : %.vsh 190 | #--------------------------------------------------------------------------------- 191 | @echo $(notdir $<) 192 | @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin 193 | @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ 194 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h 195 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h 196 | @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h 197 | @rm ../$(notdir $<).shbin 198 | 199 | -include $(DEPENDS) 200 | 201 | #--------------------------------------------------------------------------------------- 202 | endif 203 | #--------------------------------------------------------------------------------------- 204 | -------------------------------------------------------------------------------- /lib/ctrcommon/tools/template-3ds.rsf: -------------------------------------------------------------------------------- 1 | BasicInfo: 2 | Title : "$(APP_TITLE)" 3 | CompanyCode : "00" 4 | ProductCode : "$(APP_PRODUCT_CODE)" 5 | ContentType : Application 6 | Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem 7 | 8 | TitleInfo: 9 | UniqueId : $(APP_UNIQUE_ID) 10 | Category : Application 11 | 12 | CardInfo: 13 | MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB 14 | MediaType : Card1 # Card1 / Card2 15 | CardDevice : None # NorFlash(Pick this if you use savedata) / None 16 | 17 | Option: 18 | UseOnSD : false # true if App is to be installed to SD 19 | FreeProductCode : true # Removes limitations on ProductCode 20 | MediaFootPadding : false # If true CCI files are created with padding 21 | EnableCrypt : true # Enables encryption for NCCH and CIA 22 | EnableCompress : true # Compresses exefs code 23 | 24 | ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names 25 | ReadOnly: 26 | - .rodata 27 | - RO 28 | ReadWrite: 29 | - .data 30 | - RO 31 | Text: 32 | - .init 33 | - .text 34 | - STUP_ENTRY 35 | 36 | PlainRegion: # only used with SDK ELFs 37 | #- .module_id 38 | 39 | #Rom: 40 | # Specifies the root path of the file system to include in the ROM. 41 | # HostRoot : "romfs" 42 | 43 | AccessControlInfo: 44 | # UseOtherVariationSaveData : true 45 | # UseExtSaveData : true 46 | # ExtSaveDataId: 0xffffffff 47 | # SystemSaveDataId1: 0x220 48 | # SystemSaveDataId2: 0x00040010 49 | # OtherUserSaveDataId1: 0x220 50 | # OtherUserSaveDataId2: 0x330 51 | # OtherUserSaveDataId3: 0x440 52 | # UseExtendedSaveDataAccessControl: true 53 | # AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606] 54 | FileSystemAccess: 55 | # - CategorySystemApplication 56 | # - CategoryHardwareCheck 57 | - CategoryFileSystemTool 58 | - Debug 59 | # - TwlCardBackup 60 | # - TwlNandData 61 | # - Boss 62 | - DirectSdmc 63 | # - Core 64 | # - CtrNandRo 65 | # - CtrNandRw 66 | # - CtrNandRoWrite 67 | # - CategorySystemSettings 68 | # - CardBoard 69 | # - ExportImportIvs 70 | - DirectSdmcWrite 71 | # - SwitchCleanup 72 | # - SaveDataMove 73 | # - Shop 74 | # - Shell 75 | # - CategoryHomeMenu 76 | IoAccessControl: 77 | # - FsMountNand 78 | # - FsMountNandRoWrite 79 | # - FsMountTwln 80 | # - FsMountWnand 81 | # - FsMountCardSpi 82 | # - UseSdif3 83 | # - CreateSeed 84 | # - UseCardSpi 85 | 86 | IdealProcessor : 0 87 | AffinityMask : 1 88 | 89 | Priority : 16 90 | 91 | MaxCpu : 0x9E # Default 92 | 93 | # DisableDebug : true 94 | # EnableForceDebug : false 95 | # CanWriteSharedPage : true 96 | # CanUsePrivilegedPriority : false 97 | # CanUseNonAlphabetAndNumber : true 98 | # PermitMainFunctionArgument : true 99 | # CanShareDeviceMemory : true 100 | # RunnableOnSleep : false 101 | # SpecialMemoryArrange : true 102 | 103 | CoreVersion : 2 104 | DescVersion : 2 105 | 106 | ReleaseKernelMajor : "02" 107 | ReleaseKernelMinor : "33" 108 | MemoryType : Application # Application / System / Base 109 | HandleTableSize: 512 110 | IORegisterMapping: 111 | - 1ff50000-1ff57fff 112 | - 1ff70000-1ff77fff 113 | MemoryMapping: 114 | - 1f000000-1f5fffff:r 115 | SystemCallAccess: 116 | ArbitrateAddress: 34 117 | Break: 60 118 | CancelTimer: 28 119 | ClearEvent: 25 120 | ClearTimer: 29 121 | CloseHandle: 35 122 | ConnectToPort: 45 123 | ControlMemory: 1 124 | CreateAddressArbiter: 33 125 | CreateEvent: 23 126 | CreateMemoryBlock: 30 127 | CreateMutex: 19 128 | CreateSemaphore: 21 129 | CreateThread: 8 130 | CreateTimer: 26 131 | DuplicateHandle: 39 132 | ExitProcess: 3 133 | ExitThread: 9 134 | GetCurrentProcessorNumber: 17 135 | GetHandleInfo: 41 136 | GetProcessId: 53 137 | GetProcessIdOfThread: 54 138 | GetProcessIdealProcessor: 6 139 | GetProcessInfo: 43 140 | GetResourceLimit: 56 141 | GetResourceLimitCurrentValues: 58 142 | GetResourceLimitLimitValues: 57 143 | GetSystemInfo: 42 144 | GetSystemTick: 40 145 | GetThreadContext: 59 146 | GetThreadId: 55 147 | GetThreadIdealProcessor: 15 148 | GetThreadInfo: 44 149 | GetThreadPriority: 11 150 | MapMemoryBlock: 31 151 | OutputDebugString: 61 152 | QueryMemory: 2 153 | ReleaseMutex: 20 154 | ReleaseSemaphore: 22 155 | SendSyncRequest1: 46 156 | SendSyncRequest2: 47 157 | SendSyncRequest3: 48 158 | SendSyncRequest4: 49 159 | SendSyncRequest: 50 160 | SetThreadPriority: 12 161 | SetTimer: 27 162 | SignalEvent: 24 163 | SleepThread: 10 164 | UnmapMemoryBlock: 32 165 | WaitSynchronization1: 36 166 | WaitSynchronizationN: 37 167 | InterruptNumbers: 168 | ServiceAccessControl: 169 | - APT:U 170 | - $hioFIO 171 | - $hostio0 172 | - $hostio1 173 | - ac:u 174 | - boss:U 175 | - cam:u 176 | - cecd:u 177 | - cfg:u 178 | - dlp:FKCL 179 | - dlp:SRVR 180 | - dsp::DSP 181 | - frd:u 182 | - fs:USER 183 | - gsp::Gpu 184 | - hid:USER 185 | - http:C 186 | - ir:u 187 | - mic:u 188 | - ndm:u 189 | - news:u 190 | - nwm::UDS 191 | - ptm:u 192 | - pxi:dev 193 | - soc:U 194 | - ssl:C 195 | - y2r:u 196 | - am:u 197 | - cfg:nor 198 | - csnd:SND 199 | 200 | SystemControlInfo: 201 | SaveDataSize: 0KB # It doesn't use any save data. 202 | RemasterVersion: 2 203 | StackSize: 0x40000 204 | # JumpId: 0 205 | Dependency: 206 | ac: 0x0004013000002402L 207 | am: 0x0004013000001502L 208 | boss: 0x0004013000003402L 209 | camera: 0x0004013000001602L 210 | cecd: 0x0004013000002602L 211 | cfg: 0x0004013000001702L 212 | codec: 0x0004013000001802L 213 | csnd: 0x0004013000002702L 214 | dlp: 0x0004013000002802L 215 | dsp: 0x0004013000001a02L 216 | friends: 0x0004013000003202L 217 | gpio: 0x0004013000001b02L 218 | gsp: 0x0004013000001c02L 219 | hid: 0x0004013000001d02L 220 | http: 0x0004013000002902L 221 | i2c: 0x0004013000001e02L 222 | ir: 0x0004013000003302L 223 | mcu: 0x0004013000001f02L 224 | mic: 0x0004013000002002L 225 | ndm: 0x0004013000002b02L 226 | news: 0x0004013000003502L 227 | nim: 0x0004013000002c02L 228 | nwm: 0x0004013000002d02L 229 | pdn: 0x0004013000002102L 230 | ps: 0x0004013000003102L 231 | ptm: 0x0004013000002202L 232 | ro: 0x0004013000003702L 233 | socket: 0x0004013000002e02L 234 | spi: 0x0004013000002302L 235 | ssl: 0x0004013000002f02L 236 | CommonHeaderKey: 237 | D: | 238 | jL2yO86eUQnYbXIrzgFVMm7FVze0LglZ2f5g+c42hWoEdnb5BOotaMQPBfqt 239 | aUyAEmzQPaoi/4l4V+hTJRXQfthVRqIEx27B84l8LA6Tl5Fy9PaQaQ+4yRfP 240 | g6ylH2l0EikrIVjy2uMlFgl0QJCrG+QGKHftxhaGCifdAwFNmiZuyJ/TmktZ 241 | 0RCb66lYcr2h/p2G7SnpKUliS9h9KnpmG+UEgVYQUK+4SCfByUa9PxYGpT0E 242 | nw1UcRz0gsBmdOqcgzwnAd9vVqgb42hVn6uQZyAl+j1RKiMWywZarazIR/k5 243 | Lmr4+groimSEa+3ajyoIho9WaWTDmFU3mkhA2tUDIQ== 244 | Exponent: | 245 | AQAB 246 | Modulus: | 247 | zwCcsyCgMkdlieCgQMVXA6X2jmb1ICjup0Q+jk/AydPkOgsx7I/MjUymFEkU 248 | vgXBtCKtzh3NKXtFFuW51tJ60GPOabLKuG0Qm5li+UXALrWhzWuvd5vv2FZI 249 | dTQCbrq/MFS/M02xNtwqzWiBjE/LwqIdbrDAAvX4HGy0ydaQJ1DKYeQeph5D 250 | lAGBw2nQ4izXhhuLaU3w8VQkIJHdhxIKI5gJY/20AGkG0vHD553Mh5kBINrWp 251 | CRYmmJS8DCYbAiQtKbkeUfzHViGTZuj6PwaY8Mv39PGO47a++pt45IUyCEs4/ 252 | LjMS72cyfo8tU4twRGp76SFGYejYj3wGC1f/POQw== 253 | Signature: | 254 | BOPR0jL0BOV5Zx502BuPbOvi/hvOq5ID8Dz1MQfOjkey6FKP/6cb4f9YXpm6c 255 | ZCHAZLo0GduKdMepiKPUq1rsbbAxkRdQdjOOusEWoxNA58x3E4373tCAhlqM2 256 | DvuQERrIIQ/XnYLV9C3uw4efZwhFqog1jvVyoEHpuvs8xnYtGbsKQ8FrgLwXv 257 | pOZYy9cSgq+jqLy2D9IxiowPcbq2cRlbW9d2xlUfpq0AohyuXQhpxn7d9RUor 258 | 9veoARRAdxRJK12EpcSoEM1LhTRYdJnSRCY3x3p6YIV3c+l1sWvaQwKt0sZ/U 259 | 8TTDx2gb9g7r/+U9icneu/zlqUpSkexCS009Q== 260 | Descriptor: | 261 | AP///wAABAACAAAAAAAFGJ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 262 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjIAAAAAAAABBUFQ6VQAAACRoaW 263 | 9GSU8AJGhvc3RpbzAkaG9zdGlvMWFjOnUAAAAAYm9zczpVAABjYW06dQAAAGN 264 | lY2Q6dQAAY2ZnOnUAAABkbHA6RktDTGRscDpTUlZSZHNwOjpEU1BmcmQ6dQAA 265 | AGZzOlVTRVIAZ3NwOjpHcHVoaWQ6VVNFUmh0dHA6QwAAaXI6dQAAAABtaWM6d 266 | QAAAG5kbTp1AAAAbmV3czp1AABud206OlVEU3B0bTp1AAAAcHhpOmRldgBzb2 267 | M6VQAAAHNzbDpDAAAAeTJyOnUAAABhbTp1AAAAAGNmZzpub3IAY3NuZDpTTkQ 268 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 269 | AABOn/rw/7//8ec/APIA8JH/APaR/1D/gf9Y/4H/cP+B/3j/gf8BAQD/AAIA/ 270 | iECAPz/////////////////////////////////////////////////////// 271 | //////////////////////////////AAAAAAAAAAAAAAAAAAAAAAADAAAAAAA 272 | AAAAAAAAAAAI= 273 | -------------------------------------------------------------------------------- /lib/ctrcommon/tools/make_base: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITPRO)),) 6 | $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") 7 | endif 8 | 9 | ifeq ($(strip $(DEVKITARM)),) 10 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 11 | endif 12 | 13 | CTRCOMMON = $(DEVKITPRO)/ctrcommon 14 | 15 | TOPDIR ?= $(CURDIR) 16 | include $(DEVKITARM)/3ds_rules 17 | 18 | include $(TOPDIR)/resources/AppInfo 19 | 20 | APP_TITLE := $(shell echo "$(APP_TITLE)" | cut -c1-128) 21 | APP_DESCRIPTION := $(shell echo "$(APP_DESCRIPTION)" | cut -c1-256) 22 | APP_AUTHOR := $(shell echo "$(APP_AUTHOR)" | cut -c1-128) 23 | APP_PRODUCT_CODE := $(shell echo $(APP_PRODUCT_CODE) | cut -c1-16) 24 | APP_UNIQUE_ID := $(shell echo $(APP_UNIQUE_ID) | cut -c1-7) 25 | 26 | BUILD := build 27 | SOURCES := source 28 | DATA := data 29 | INCLUDES := $(SOURCES) include 30 | ICON := resources/icon.png 31 | 32 | #--------------------------------------------------------------------------------- 33 | # options for code generation 34 | #--------------------------------------------------------------------------------- 35 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 36 | 37 | COMMON_FLAGS := -g -Wall -Wno-strict-aliasing -O3 -mword-relocations -fomit-frame-pointer -ffast-math $(ARCH) $(INCLUDE) -DARM11 -D_3DS $(BUILD_FLAGS) 38 | 39 | CXXFLAGS := $(COMMON_FLAGS) -std=gnu++11 40 | ifeq ($(ENABLE_EXCEPTIONS),) 41 | CXXFLAGS += -fno-rtti -fno-exceptions 42 | endif 43 | 44 | CFLAGS := $(COMMON_FLAGS) -std=gnu99 45 | 46 | ASFLAGS := -g $(ARCH) 47 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 48 | 49 | LIBS := -lctru -lm 50 | LIBDIRS := $(PORTLIBS) $(CTRULIB) ./lib 51 | ifeq ($(NO_CTRCOMMON),) 52 | LIBS := -lctrcommon -lctru -lm 53 | LIBDIRS := $(CTRCOMMON) $(PORTLIBS) $(CTRULIB) ./lib 54 | endif 55 | 56 | RSF_3DS = $(CTRCOMMON)/tools/template-3ds.rsf 57 | RSF_CIA = $(CTRCOMMON)/tools/template-cia.rsf 58 | 59 | ifeq ($(OS),Windows_NT) 60 | MAKEROM = $(CTRCOMMON)/tools/makerom.exe 61 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool.exe 62 | else 63 | UNAME_S := $(shell uname -s) 64 | ifeq ($(UNAME_S),Linux) 65 | MAKEROM = $(CTRCOMMON)/tools/makerom-linux 66 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool-linux 67 | endif 68 | ifeq ($(UNAME_S),Darwin) 69 | MAKEROM = $(CTRCOMMON)/tools/makerom-mac 70 | BANNERTOOL = $(CTRCOMMON)/tools/bannertool-mac 71 | endif 72 | endif 73 | 74 | ifneq ("$(wildcard $(TOPDIR)/resources/banner.cgfx)","") 75 | BANNER_IMAGE := $(TOPDIR)/resources/banner.cgfx 76 | BANNER_IMAGE_ARG := -ci $(BANNER_IMAGE) 77 | else 78 | BANNER_IMAGE := $(TOPDIR)/resources/banner.png 79 | BANNER_IMAGE_ARG := -i $(BANNER_IMAGE) 80 | endif 81 | 82 | #--------------------------------------------------------------------------------- 83 | # no real need to edit anything past this point unless you need to add additional 84 | # rules for different file extensions 85 | #--------------------------------------------------------------------------------- 86 | ifneq ($(BUILD),$(notdir $(CURDIR))) 87 | #--------------------------------------------------------------------------------- 88 | 89 | recurse = $(shell find $2 -type $1 -name '$3' 2> /dev/null) 90 | 91 | null := 92 | SPACE := $(null) $(null) 93 | export OUTPUT_D := $(CURDIR)/output 94 | export OUTPUT_N := $(subst $(SPACE),,$(APP_TITLE)) 95 | export OUTPUT := $(OUTPUT_D)/$(OUTPUT_N) 96 | export TOPDIR := $(CURDIR) 97 | 98 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir) $(call recurse,d,$(CURDIR)/$(dir),*)) \ 99 | $(foreach dir,$(DATA),$(CURDIR)/$(dir) $(call recurse,d,$(CURDIR)/$(dir),*)) 100 | 101 | export DEPSDIR := $(CURDIR)/$(BUILD) 102 | 103 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.c))) 104 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.cpp))) 105 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(call recurse,f,$(dir),*.s))) 106 | BINFILES := $(foreach dir,$(DATA),$(notdir $(call recurse,f,$(dir),*.*))) 107 | 108 | #--------------------------------------------------------------------------------- 109 | # use CXX for linking C++ projects, CC for standard C 110 | #--------------------------------------------------------------------------------- 111 | ifeq ($(strip $(CPPFILES)),) 112 | #--------------------------------------------------------------------------------- 113 | export LD := $(CC) 114 | #--------------------------------------------------------------------------------- 115 | else 116 | #--------------------------------------------------------------------------------- 117 | export LD := $(CXX) 118 | #--------------------------------------------------------------------------------- 119 | endif 120 | #--------------------------------------------------------------------------------- 121 | 122 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 123 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 124 | 125 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 126 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 127 | -I$(CURDIR)/$(BUILD) 128 | 129 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 130 | 131 | export APP_ICON := $(TOPDIR)/$(ICON) 132 | 133 | .PHONY: $(BUILD) clean all 134 | 135 | #--------------------------------------------------------------------------------- 136 | all: $(BUILD) 137 | 138 | $(BUILD): 139 | @[ -d $@ ] || mkdir -p $@ 140 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 141 | 142 | #--------------------------------------------------------------------------------- 143 | clean: 144 | @echo clean ... 145 | @rm -fr $(BUILD) $(OUTPUT_D) 146 | 147 | 148 | #--------------------------------------------------------------------------------- 149 | else 150 | 151 | DEPENDS := $(OFILES:.o=.d) 152 | 153 | #--------------------------------------------------------------------------------- 154 | # main targets 155 | #--------------------------------------------------------------------------------- 156 | .PHONY: all 157 | all: $(OUTPUT).zip 158 | 159 | $(OUTPUT_D): 160 | @[ -d $@ ] || mkdir -p $@ 161 | 162 | banner.bnr: $(BANNER_IMAGE) $(TOPDIR)/resources/audio.wav 163 | @$(BANNERTOOL) makebanner $(BANNER_IMAGE_ARG) -a $(TOPDIR)/resources/audio.wav -o banner.bnr > /dev/null 164 | 165 | icon.icn: $(TOPDIR)/resources/icon.png 166 | @$(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_TITLE)" -p "$(APP_AUTHOR)" -i $(TOPDIR)/resources/icon.png -o icon.icn > /dev/null 167 | 168 | $(OUTPUT).elf: $(OFILES) 169 | 170 | stripped.elf: $(OUTPUT).elf 171 | @cp $(OUTPUT).elf stripped.elf 172 | @$(PREFIX)strip stripped.elf 173 | 174 | $(OUTPUT).3dsx: stripped.elf 175 | 176 | $(OUTPUT).3ds: stripped.elf banner.bnr icon.icn 177 | @$(MAKEROM) -f cci -o $(OUTPUT).3ds -rsf $(RSF_3DS) -target d -exefslogo -elf stripped.elf -icon icon.icn -banner banner.bnr -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(APP_PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(APP_UNIQUE_ID)" 178 | @echo "built ... $(notdir $@)" 179 | 180 | $(OUTPUT).cia: stripped.elf banner.bnr icon.icn 181 | @$(MAKEROM) -f cia -o $(OUTPUT).cia -rsf $(RSF_CIA) -target t -exefslogo -elf stripped.elf -icon icon.icn -banner banner.bnr -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(APP_PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(APP_UNIQUE_ID)" 182 | @echo "built ... $(notdir $@)" 183 | 184 | $(OUTPUT).zip: $(OUTPUT_D) $(OUTPUT).elf $(OUTPUT).3dsx $(OUTPUT).smdh $(OUTPUT).3ds $(OUTPUT).cia 185 | @cd $(OUTPUT_D); \ 186 | mkdir -p 3ds/$(OUTPUT_N); \ 187 | cp $(OUTPUT_N).3dsx 3ds/$(OUTPUT_N); \ 188 | cp $(OUTPUT_N).smdh 3ds/$(OUTPUT_N); \ 189 | zip -r $(OUTPUT_N).zip $(OUTPUT_N).elf $(OUTPUT_N).3ds $(OUTPUT_N).cia 3ds > /dev/null; \ 190 | rm -r 3ds 191 | @echo "built ... $(notdir $@)" 192 | 193 | #--------------------------------------------------------------------------------- 194 | # you need a rule like this for each extension you use as binary data 195 | #--------------------------------------------------------------------------------- 196 | %.bin.o : %.bin 197 | #--------------------------------------------------------------------------------- 198 | @echo $(notdir $<) 199 | @$(bin2o) 200 | 201 | # WARNING: This is not the right way to do this! TODO: Do it right! 202 | #--------------------------------------------------------------------------------- 203 | %.vsh.o : %.vsh 204 | #--------------------------------------------------------------------------------- 205 | @echo $(notdir $<) 206 | @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin 207 | @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ 208 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h 209 | @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h 210 | @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h 211 | @rm ../$(notdir $<).shbin 212 | 213 | -include $(DEPENDS) 214 | 215 | #--------------------------------------------------------------------------------------- 216 | endif 217 | #--------------------------------------------------------------------------------------- 218 | -------------------------------------------------------------------------------- /lib/ctrcommon/include/ctrcommon/gpu.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CTRCOMMON_GPU_HPP__ 2 | #define __CTRCOMMON_GPU_HPP__ 3 | 4 | #include "ctrcommon/types.hpp" 5 | 6 | #include 7 | 8 | #define TOP_WIDTH 400 9 | #define TOP_HEIGHT 240 10 | #define BOTTOM_WIDTH 320 11 | #define BOTTOM_HEIGHT 240 12 | 13 | #define ATTRIBUTE(i, n, f) (((((n)-1)<<2)|((f)&3))<<((i)*4)) 14 | 15 | #define TEXENV_SOURCES(a,b,c) (((a))|((b)<<4)|((c)<<8)) 16 | #define TEXENV_OPERANDS(a,b,c) (((a))|((b)<<4)|((c)<<8)) 17 | 18 | #define TEXTURE_MAG_FILTER(v) (((v)&0x1)<<1) 19 | #define TEXTURE_MIN_FILTER(v) (((v)&0x1)<<2) 20 | #define TEXTURE_WRAP_S(v) (((v)&0x3)<<8) 21 | #define TEXTURE_WRAP_T(v) (((v)&0x3)<<12) 22 | 23 | typedef enum { 24 | TOP_SCREEN, 25 | BOTTOM_SCREEN 26 | } Screen; 27 | 28 | typedef enum { 29 | LEFT_SCREEN, 30 | RIGHT_SCREEN 31 | } ScreenSide; 32 | 33 | typedef enum { 34 | CULL_NONE = 0x0, 35 | CULL_FRONT_CCW = 0x1, 36 | CULL_BACK_CCW = 0x2 37 | } CullMode; 38 | 39 | typedef enum { 40 | TEST_NEVER = 0x0, 41 | TEST_ALWAYS = 0x1, 42 | TEST_EQUAL = 0x2, 43 | TEST_NOTEQUAL = 0x3, 44 | TEST_LESS = 0x4, 45 | TEST_LEQUAL = 0x5, 46 | TEST_GREATER = 0x6, 47 | TEST_GEQUAL = 0x7 48 | } TestFunc; 49 | 50 | typedef enum { 51 | STENCIL_OP_KEEP = 0x0, 52 | STENCIL_OP_AND_NOT = 0x1, 53 | STENCIL_OP_XOR = 0x5 54 | } StencilOp; 55 | 56 | typedef enum { 57 | BLEND_ADD = 0x0, 58 | BLEND_SUBTRACT = 0x1, 59 | BLEND_REVERSE_SUBTRACT = 0x2, 60 | BLEND_MIN = 0x3, 61 | BLEND_MAX = 0x4 62 | } BlendEquation; 63 | 64 | typedef enum { 65 | FACTOR_ZERO = 0x0, 66 | FACTOR_ONE = 0x1, 67 | FACTOR_SRC_COLOR = 0x2, 68 | FACTOR_ONE_MINUS_SRC_COLOR = 0x3, 69 | FACTOR_DST_COLOR = 0x4, 70 | FACTOR_ONE_MINUS_DST_COLOR = 0x5, 71 | FACTOR_SRC_ALPHA = 0x6, 72 | FACTOR_ONE_MINUS_SRC_ALPHA = 0x7, 73 | FACTOR_DST_ALPHA = 0x8, 74 | FACTOR_ONE_MINUS_DST_ALPHA = 0x9, 75 | FACTOR_CONSTANT_COLOR = 0xA, 76 | FACTOR_ONE_MINUS_CONSTANT_COLOR = 0xB, 77 | FACTOR_CONSTANT_ALPHA = 0xC, 78 | FACTOR_ONE_MINUS_CONSTANT_ALPHA = 0xD, 79 | FACTOR_SRC_ALPHA_SATURATE = 0xE 80 | } BlendFactor; 81 | 82 | typedef enum { 83 | VERTEX_SHADER = 0x0, 84 | GEOMETRY_SHADER = 0x1 85 | } ShaderType; 86 | 87 | typedef enum { 88 | PRIM_TRIANGLES = 0x0000, 89 | PRIM_TRIANGLE_STRIP = 0x0100, 90 | PRIM_TRIANGLE_FAN = 0x0200, 91 | PRIM_UNKPRIM = 0x0300 92 | } Primitive; 93 | 94 | typedef enum { 95 | ATTR_BYTE = 0x0, 96 | ATTR_UNSIGNED_BYTE = 0x1, 97 | ATTR_SHORT = 0x2, 98 | ATTR_FLOAT = 0x3 99 | } AttributeType; 100 | 101 | typedef enum{ 102 | SOURCE_PRIMARY_COLOR = 0x0, 103 | SOURCE_TEXTURE0 = 0x3, 104 | SOURCE_TEXTURE1 = 0x4, 105 | SOURCE_TEXTURE2 = 0x5, 106 | SOURCE_TEXTURE3 = 0x6, 107 | SOURCE_CONSTANT = 0xE, 108 | SOURCE_PREVIOUS = 0xF 109 | } TexEnvSource; 110 | 111 | typedef enum { 112 | TEXENV_OP_RGB_SRC_COLOR = 0x00, 113 | TEXENV_OP_RGB_ONE_MINUS_SRC_COLOR = 0x01, 114 | TEXENV_OP_RGB_SRC_ALPHA = 0x02, 115 | TEXENV_OP_RGB_ONE_MINUS_SRC_ALPHA = 0x03, 116 | TEXENV_OP_RGB_SRC0_RGB = 0x04, 117 | TEXENV_OP_RGB_0x05 = 0x05, 118 | TEXENV_OP_RGB_0x06 = 0x06, 119 | TEXENV_OP_RGB_0x07 = 0x07, 120 | TEXENV_OP_RGB_SRC1_RGB = 0x08, 121 | TEXENV_OP_RGB_0x09 = 0x09, 122 | TEXENV_OP_RGB_0x0A = 0x0A, 123 | TEXENV_OP_RGB_0x0B = 0x0B, 124 | TEXENV_OP_RGB_SRC2_RGB = 0x0C, 125 | TEXENV_OP_RGB_0x0D = 0x0D, 126 | TEXENV_OP_RGB_0x0E = 0x0E, 127 | TEXENV_OP_RGB_0x0F = 0x0F, 128 | } TexEnvOpRGB; 129 | 130 | typedef enum { 131 | TEXENV_OP_A_SRC_ALPHA = 0x00, 132 | TEXENV_OP_A_ONE_MINUS_SRC_ALPHA = 0x01, 133 | TEXENV_OP_A_SRC0_RGB = 0x02, 134 | TEXENV_OP_A_SRC1_RGB = 0x04, 135 | TEXENV_OP_A_SRC2_RGB = 0x06, 136 | } TexEnvOpA; 137 | 138 | typedef enum { 139 | COMBINE_REPLACE = 0x0, 140 | COMBINE_MODULATE = 0x1, 141 | COMBINE_ADD = 0x2, 142 | COMBINE_ADD_SIGNED = 0x3, 143 | COMBINE_INTERPOLATE = 0x4, 144 | COMBINE_SUBTRACT = 0x5, 145 | COMBINE_DOT3_RGB = 0x6 146 | } CombineFunc; 147 | 148 | typedef enum { 149 | TEXUNIT0 = 0x1, 150 | TEXUNIT1 = 0x2, 151 | TEXUNIT2 = 0x4 152 | } TexUnit; 153 | 154 | typedef enum { 155 | FILTER_NEAREST = 0x0, 156 | FILTER_LINEAR = 0x1 157 | } TextureFilter; 158 | 159 | typedef enum { 160 | WRAP_CLAMP_TO_EDGE = 0x0, 161 | WRAP_REPEAT = 0x2 162 | } TextureWrap; 163 | 164 | typedef enum { 165 | PIXEL_RGBA8 = 0x0, 166 | PIXEL_RGB8 = 0x1, 167 | PIXEL_RGBA5551 = 0x2, 168 | PIXEL_RGB565 = 0x3, 169 | PIXEL_RGBA4 = 0x4, 170 | PIXEL_LA8 = 0x5, 171 | PIXEL_HILO8 = 0x6, 172 | PIXEL_L8 = 0x7, 173 | PIXEL_A8 = 0x8, 174 | PIXEL_LA4 = 0x9, 175 | PIXEL_L4 = 0xA, 176 | PIXEL_A4 = 0xB, 177 | PIXEL_ETC1 = 0xC, 178 | PIXEL_ETC1A4 = 0xD 179 | } PixelFormat; 180 | 181 | typedef enum { 182 | SCISSOR_DISABLE = 0x0, 183 | SCISSOR_INVERT = 0x1, 184 | SCISSOR_NORMAL = 0x3 185 | } ScissorMode; 186 | 187 | void* gpuAlloc(u32 size); 188 | void gpuFree(void* mem); 189 | 190 | void gpuFlush(); 191 | void gpuFlushBuffer(); 192 | void gpuSwapBuffers(bool vblank); 193 | 194 | void gpuClearScreens(); 195 | void gpuClear(); 196 | 197 | void gpuClearColor(u8 red, u8 green, u8 blue, u8 alpha); 198 | void gpuClearDepth(u32 depth); 199 | 200 | void gpuSet3d(bool enable3d); 201 | void gpuScreenSide(ScreenSide side); 202 | 203 | int gpuGetViewportWidth(); 204 | int gpuGetViewportHeight(); 205 | 206 | void gpuViewport(Screen screen, u32 x, u32 y, u32 width, u32 height); 207 | void gpuScissorTest(ScissorMode mode, u32 x, u32 y, u32 width, u32 height); 208 | void gpuDepthMap(float near, float far); 209 | 210 | void gpuCullMode(CullMode mode); 211 | 212 | void gpuStencilTest(bool enable, TestFunc func, u8 ref, u8 mask, u8 replace); 213 | void gpuStencilOp(StencilOp fail, StencilOp zfail, StencilOp zpass); 214 | 215 | void gpuBlendColor(u8 red, u8 green, u8 blue, u8 alpha); 216 | void gpuBlendFunc(BlendEquation colorEquation, BlendEquation alphaEquation, BlendFactor colorSrc, BlendFactor colorDst, BlendFactor alphaSrc, BlendFactor alphaDst); 217 | 218 | void gpuAlphaTest(bool enable, TestFunc func, u8 ref); 219 | 220 | void gpuDepthTest(bool enable, TestFunc func); 221 | 222 | void gpuColorMask(bool red, bool green, bool blue, bool alpha); 223 | void gpuDepthMask(bool depth); 224 | 225 | void gpuCreateShader(u32* shader); 226 | void gpuFreeShader(u32 shader); 227 | void gpuLoadShader(u32 shader, const void* data, u32 size, u8 geometryStride = 0); 228 | void gpuUseShader(u32 shader); 229 | void gpuGetUniformBool(u32 shader, ShaderType type, int id, bool* value); 230 | void gpuSetUniformBool(u32 shader, ShaderType type, int id, bool value); 231 | void gpuSetUniform(u32 shader, ShaderType type, const char* name, const float* data, u32 elements); 232 | 233 | void gpuCreateVbo(u32* vbo); 234 | void gpuFreeVbo(u32 vbo); 235 | void* gpuGetVboData(u32 vbo); 236 | void gpuVboDataInfo(u32 vbo, u32 numVertices, Primitive primitive); 237 | void gpuVboData(u32 vbo, const void* data, u32 numVertices, Primitive primitive); 238 | void* gpuGetVboIndices(u32 vbo); 239 | void gpuVboIndicesInfo(u32 vbo, u32 size); 240 | void gpuVboIndices(u32 vbo, const void* data, u32 size); 241 | void gpuVboAttributes(u32 vbo, u64 attributes, u8 attributeCount); 242 | void gpuDrawVbo(u32 vbo); 243 | 244 | inline u32 gpuTextureIndex(u32 x, u32 y, u32 w, u32 h) { 245 | return (((y >> 3) * (w >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3)); 246 | } 247 | 248 | void gpuTexEnv(u32 env, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, CombineFunc rgbCombine, CombineFunc alphaCombine, u32 constantColor); 249 | void gpuCreateTexture(u32* texture); 250 | void gpuFreeTexture(u32 texture); 251 | void* gpuGetTextureData(u32 texture); 252 | void gpuTextureInfo(u32 texture, u32 width, u32 height, PixelFormat format, u32 params); 253 | void gpuTextureData(u32 texture, const void* data, u32 width, u32 height, PixelFormat format, u32 params); 254 | void gpuBindTexture(TexUnit unit, u32 texture); 255 | 256 | // GPUT - GPU Tools 257 | 258 | void gputUseDefaultShader(); 259 | 260 | void gputMultMatrix4(float* out, const float* m1, const float* m2); 261 | void gputIdentityMatrix(float *out); 262 | void gputOrthoMatrix(float* out, float left, float right, float bottom, float top, float near, float far); 263 | void gputPerspectiveMatrix(float* out, float fovy, float aspect, float near, float far); 264 | void gputTranslationMatrix(float* out, float x, float y, float z); 265 | void gputRotationMatrixX(float* out, float rotation); 266 | void gputRotationMatrixY(float* out, float rotation); 267 | void gputRotationMatrixZ(float* out, float rotation); 268 | void gputScaleMatrix(float *out, float x, float y, float z); 269 | 270 | void gputPushProjection(); 271 | void gputPopProjection(); 272 | float* gputGetProjection(); 273 | void gputProjection(float* matrix); 274 | void gputOrtho(float left, float right, float bottom, float top, float near, float far); 275 | void gputPerspective(float fovy, float aspect, float near, float far); 276 | 277 | void gputPushModelView(); 278 | void gputPopModelView(); 279 | float* gputGetModelView(); 280 | void gputModelView(float* matrix); 281 | void gputTranslate(float x, float y, float z); 282 | void gputRotateX(float rotation); 283 | void gputRotateY(float rotation); 284 | void gputRotateZ(float rotation); 285 | void gputRotate(float x, float y, float z); 286 | void gputScale(float x, float y, float z); 287 | 288 | float gputGetStringWidth(const std::string str, float charWidth); 289 | float gputGetStringHeight(const std::string str, float charHeight); 290 | void gputDrawString(const std::string str, float x, float y, float charWidth, float charHeight, u8 red = 0xFF, u8 green = 0xFF, u8 blue = 0xFF, u8 alpha = 0xFF); 291 | 292 | void gputTakeScreenshot(); 293 | 294 | #endif -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/app.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/app.hpp" 2 | 3 | #include "service.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include <3ds.h> 15 | #include 16 | 17 | u8 appMediatypeToByte(MediaType mediaType) { 18 | return mediaType == NAND ? mediatype_NAND : mediatype_SDMC; 19 | } 20 | 21 | AppPlatform appPlatformFromId(u16 id) { 22 | switch(id) { 23 | case 1: 24 | return PLATFORM_WII; 25 | case 3: 26 | return PLATFORM_DSI; 27 | case 4: 28 | return PLATFORM_3DS; 29 | case 5: 30 | return PLATFORM_WIIU; 31 | default: 32 | return PLATFORM_UNKNOWN; 33 | } 34 | } 35 | 36 | AppCategory appCategoryFromId(u16 id) { 37 | if((id & 0x8000) == 0x8000) { 38 | return CATEGORY_TWL; 39 | } else if((id & 0x10) == 0x10) { 40 | return CATEGORY_SYSTEM; 41 | } else if((id & 0x6) == 0x6) { 42 | return CATEGORY_PATCH; 43 | } else if((id & 0x4) == 0x4) { 44 | return CATEGORY_DLC; 45 | } else if((id & 0x2) == 0x2) { 46 | return CATEGORY_DEMO; 47 | } 48 | 49 | return CATEGORY_APP; 50 | } 51 | 52 | const std::string appGetResultString(AppResult result) { 53 | std::stringstream resultMsg; 54 | if(result == APP_SUCCESS) { 55 | resultMsg << "Operation succeeded."; 56 | } else if(result == APP_PROCESS_CLOSING) { 57 | resultMsg << "Process closing."; 58 | } else if(result == APP_OPERATION_CANCELLED) { 59 | resultMsg << "Operation cancelled."; 60 | } else if(result == APP_AM_INIT_FAILED) { 61 | resultMsg << "Could not initialize AM service."; 62 | } else if(result == APP_IO_ERROR) { 63 | resultMsg << "I/O Error." << "\n" << strerror(errno); 64 | } else if(result == APP_OPEN_FILE_FAILED) { 65 | resultMsg << "Could not open file." << "\n" << strerror(errno); 66 | } else if(result == APP_BEGIN_INSTALL_FAILED) { 67 | resultMsg << "Could not begin installation." << "\n" << platformGetErrorString(platformGetError()); 68 | } else if(result == APP_INSTALL_ERROR) { 69 | resultMsg << "Could not install app." << "\n" << platformGetErrorString(platformGetError()); 70 | } else if(result == APP_FINALIZE_INSTALL_FAILED) { 71 | resultMsg << "Could not finalize installation." << "\n" << platformGetErrorString(platformGetError()); 72 | } else if(result == APP_DELETE_FAILED) { 73 | resultMsg << "Could not delete app." << "\n" << platformGetErrorString(platformGetError()); 74 | } else if(result == APP_LAUNCH_FAILED) { 75 | resultMsg << "Could not launch app." << "\n" << platformGetErrorString(platformGetError()); 76 | } else { 77 | resultMsg << "Unknown error."; 78 | } 79 | 80 | return resultMsg.str(); 81 | } 82 | 83 | const std::string appGetPlatformName(AppPlatform platform) { 84 | switch(platform) { 85 | case PLATFORM_WII: 86 | return "Wii"; 87 | case PLATFORM_DSI: 88 | return "DSi"; 89 | case PLATFORM_3DS: 90 | return "3DS"; 91 | case PLATFORM_WIIU: 92 | return "Wii U"; 93 | default: 94 | return "Unknown"; 95 | } 96 | } 97 | 98 | const std::string appGetCategoryName(AppCategory category) { 99 | switch(category) { 100 | case CATEGORY_APP: 101 | return "App"; 102 | case CATEGORY_DEMO: 103 | return "Demo"; 104 | case CATEGORY_DLC: 105 | return "DLC"; 106 | case CATEGORY_PATCH: 107 | return "Patch"; 108 | case CATEGORY_SYSTEM: 109 | return "System"; 110 | case CATEGORY_TWL: 111 | return "TWL"; 112 | default: 113 | return "Unknown"; 114 | } 115 | } 116 | 117 | App appGetCiaInfo(const std::string file, MediaType mediaType) { 118 | if(!serviceRequire("am")) { 119 | return {}; 120 | } 121 | 122 | FS_archive archive = (FS_archive) {ARCH_SDMC, (FS_path) {PATH_EMPTY, 1, (u8*) ""}}; 123 | Result archiveResult = FSUSER_OpenArchive(NULL, &archive); 124 | if(archiveResult != 0) { 125 | platformSetError(serviceParseError((u32) archiveResult)); 126 | return {}; 127 | } 128 | 129 | Handle handle = 0; 130 | Result openResult = FSUSER_OpenFile(NULL, &handle, archive, FS_makePath(PATH_CHAR, file.c_str()), FS_OPEN_READ, FS_ATTRIBUTE_NONE); 131 | if(openResult != 0) { 132 | platformSetError(serviceParseError((u32) openResult)); 133 | return {}; 134 | } 135 | 136 | TitleList titleInfo; 137 | Result infoResult = AM_GetCiaFileInfo(appMediatypeToByte(mediaType), &titleInfo, handle); 138 | if(infoResult != 0) { 139 | platformSetError(serviceParseError((u32) infoResult)); 140 | return {}; 141 | } 142 | 143 | FSFILE_Close(handle); 144 | FSUSER_CloseArchive(NULL, &archive); 145 | 146 | App app; 147 | app.titleId = titleInfo.titleID; 148 | app.uniqueId = ((u32*) &titleInfo.titleID)[0]; 149 | strcpy(app.productCode, ""); 150 | app.mediaType = mediaType; 151 | app.platform = appPlatformFromId(((u16*) &titleInfo.titleID)[3]); 152 | app.category = appCategoryFromId(((u16*) &titleInfo.titleID)[2]); 153 | app.version = titleInfo.titleVersion; 154 | app.size = titleInfo.size; 155 | return app; 156 | } 157 | 158 | bool appIsInstalled(App app) { 159 | if(!serviceRequire("am")) { 160 | return false; 161 | } 162 | 163 | u32 titleCount; 164 | Result titleCountResult = AM_GetTitleCount(appMediatypeToByte(app.mediaType), &titleCount); 165 | if(titleCountResult != 0) { 166 | platformSetError(serviceParseError((u32) titleCountResult)); 167 | return false; 168 | } 169 | 170 | u64 titleIds[titleCount]; 171 | Result titleIdsResult = AM_GetTitleIdList(appMediatypeToByte(app.mediaType), titleCount, titleIds); 172 | if(titleIdsResult != 0) { 173 | platformSetError(serviceParseError((u32) titleIdsResult)); 174 | return false; 175 | } 176 | 177 | for(u32 i = 0; i < titleCount; i++) { 178 | if(titleIds[i] == app.titleId) { 179 | return true; 180 | } 181 | } 182 | 183 | return false; 184 | } 185 | 186 | std::vector appList(MediaType mediaType) { 187 | std::vector titles; 188 | if(!serviceRequire("am")) { 189 | return titles; 190 | } 191 | 192 | u32 titleCount; 193 | Result titleCountResult = AM_GetTitleCount(appMediatypeToByte(mediaType), &titleCount); 194 | if(titleCountResult != 0) { 195 | platformSetError(serviceParseError((u32) titleCountResult)); 196 | return titles; 197 | } 198 | 199 | u64 titleIds[titleCount]; 200 | Result titleIdsResult = AM_GetTitleIdList(appMediatypeToByte(mediaType), titleCount, titleIds); 201 | if(titleIdsResult != 0) { 202 | platformSetError(serviceParseError((u32) titleIdsResult)); 203 | return titles; 204 | } 205 | 206 | TitleList titleList[titleCount]; 207 | Result titleListResult = AM_ListTitles(appMediatypeToByte(mediaType), titleCount, titleIds, titleList); 208 | if(titleListResult != 0) { 209 | platformSetError(serviceParseError((u32) titleListResult)); 210 | return titles; 211 | } 212 | 213 | for(u32 i = 0; i < titleCount; i++) { 214 | u64 titleId = titleList[i].titleID; 215 | 216 | App app; 217 | app.titleId = titleId; 218 | app.uniqueId = ((u32*) &titleId)[0]; 219 | AM_GetTitleProductCode(appMediatypeToByte(mediaType), titleId, app.productCode); 220 | if(strcmp(app.productCode, "") == 0) { 221 | strcpy(app.productCode, ""); 222 | } 223 | 224 | app.mediaType = mediaType; 225 | app.platform = appPlatformFromId(((u16*) &titleId)[3]); 226 | app.category = appCategoryFromId(((u16*) &titleId)[2]); 227 | app.version = titleList[i].titleVersion; 228 | app.size = titleList[i].size; 229 | 230 | titles.push_back(app); 231 | } 232 | 233 | return titles; 234 | } 235 | 236 | AppResult appInstallFile(MediaType mediaType, const std::string path, std::function onProgress) { 237 | if(!serviceRequire("am")) { 238 | return APP_AM_INIT_FAILED; 239 | } 240 | 241 | FILE* fd = fopen(path.c_str(), "r"); 242 | if(!fd) { 243 | return APP_OPEN_FILE_FAILED; 244 | } 245 | 246 | struct stat st; 247 | stat(path.c_str(), &st); 248 | u64 size = (u64) (u32) st.st_size; 249 | 250 | AppResult ret = appInstall(mediaType, fd, size, onProgress); 251 | 252 | fclose(fd); 253 | return ret; 254 | } 255 | 256 | AppResult appInstall(MediaType mediaType, FILE* fd, u64 size, std::function onProgress) { 257 | if(!serviceRequire("am")) { 258 | return APP_AM_INIT_FAILED; 259 | } 260 | 261 | if(onProgress != NULL) { 262 | onProgress(0, size); 263 | } 264 | 265 | Handle ciaHandle; 266 | Result startResult = AM_StartCiaInstall(appMediatypeToByte(mediaType), &ciaHandle); 267 | if(startResult != 0) { 268 | platformSetError(serviceParseError((u32) startResult)); 269 | return APP_BEGIN_INSTALL_FAILED; 270 | } 271 | 272 | u32 bufSize = 1024 * 128; // 128KB 273 | void* buf = malloc(bufSize); 274 | bool cancelled = false; 275 | u64 pos = 0; 276 | while(platformIsRunning()) { 277 | if(onProgress != NULL && !onProgress(pos, size)) { 278 | cancelled = true; 279 | break; 280 | } 281 | 282 | size_t bytesRead = fread(buf, 1, bufSize, fd); 283 | if(bytesRead > 0) { 284 | Result writeResult = FSFILE_Write(ciaHandle, NULL, pos, buf, (u32) bytesRead, FS_WRITE_NOFLUSH); 285 | if(writeResult != 0) { 286 | AM_CancelCIAInstall(&ciaHandle); 287 | platformSetError(serviceParseError((u32) writeResult)); 288 | return APP_INSTALL_ERROR; 289 | } 290 | 291 | pos += bytesRead; 292 | } 293 | 294 | if((ferror(fd) && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) || (size != 0 && pos == size)) { 295 | break; 296 | } 297 | } 298 | 299 | free(buf); 300 | 301 | if(cancelled) { 302 | AM_CancelCIAInstall(&ciaHandle); 303 | return APP_OPERATION_CANCELLED; 304 | } 305 | 306 | if(!platformIsRunning()) { 307 | AM_CancelCIAInstall(&ciaHandle); 308 | return APP_PROCESS_CLOSING; 309 | } 310 | 311 | if(size != 0 && pos != size) { 312 | AM_CancelCIAInstall(&ciaHandle); 313 | return APP_IO_ERROR; 314 | } 315 | 316 | if(onProgress != NULL) { 317 | onProgress(size, size); 318 | } 319 | 320 | Result finishResult = AM_FinishCiaInstall(appMediatypeToByte(mediaType), &ciaHandle); 321 | if(finishResult != 0) { 322 | platformSetError(serviceParseError((u32) finishResult)); 323 | return APP_FINALIZE_INSTALL_FAILED; 324 | } 325 | 326 | return APP_SUCCESS; 327 | } 328 | 329 | AppResult appDelete(App app) { 330 | if(!serviceRequire("am")) { 331 | return APP_AM_INIT_FAILED; 332 | } 333 | 334 | Result res = AM_DeleteTitle(appMediatypeToByte(app.mediaType), app.titleId); 335 | if(res != 0) { 336 | platformSetError(serviceParseError((u32) res)); 337 | return APP_DELETE_FAILED; 338 | } 339 | 340 | return APP_SUCCESS; 341 | } 342 | 343 | AppResult appLaunch(App app) { 344 | u8 buf0[0x300]; 345 | u8 buf1[0x20]; 346 | 347 | aptOpenSession(); 348 | Result prepareResult = APT_PrepareToDoAppJump(NULL, 0, app.titleId, appMediatypeToByte(app.mediaType)); 349 | if(prepareResult != 0) { 350 | aptCloseSession(); 351 | platformSetError(serviceParseError((u32) prepareResult)); 352 | return APP_LAUNCH_FAILED; 353 | } 354 | 355 | Result doResult = APT_DoAppJump(NULL, 0x300, 0x20, buf0, buf1); 356 | if(doResult != 0) { 357 | aptCloseSession(); 358 | platformSetError(serviceParseError((u32) doResult)); 359 | return APP_LAUNCH_FAILED; 360 | } 361 | 362 | aptCloseSession(); 363 | return APP_SUCCESS; 364 | } -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/gput.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/gpu.hpp" 2 | #include "ctrcommon/platform.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include <3ds.h> 12 | #include 13 | 14 | #include "ctrcommon_shader_vsh_shbin.h" 15 | #include "ctrcommon_font_bin.h" 16 | 17 | u32 defaultShader = 0; 18 | u32 stringVbo = 0; 19 | u32 dummyTexture = 0; 20 | u32 fontTexture = 0; 21 | 22 | float projection[16] = {0}; 23 | float modelview[16] = {0}; 24 | 25 | std::stack projectionStack; 26 | std::stack modelviewStack; 27 | 28 | void gputInit() { 29 | gpuCreateShader(&defaultShader); 30 | gpuLoadShader(defaultShader, ctrcommon_shader_vsh_shbin, ctrcommon_shader_vsh_shbin_size); 31 | gputUseDefaultShader(); 32 | 33 | gpuCreateVbo(&stringVbo); 34 | gpuVboAttributes(stringVbo, ATTRIBUTE(0, 3, ATTR_FLOAT) | ATTRIBUTE(1, 2, ATTR_FLOAT) | ATTRIBUTE(2, 4, ATTR_FLOAT), 3); 35 | 36 | gpuCreateTexture(&dummyTexture); 37 | gpuTextureInfo(dummyTexture, 64, 64, PIXEL_RGBA8, TEXTURE_MIN_FILTER(FILTER_NEAREST) | TEXTURE_MAG_FILTER(FILTER_NEAREST)); 38 | memset(gpuGetTextureData(dummyTexture), 0xFF, 64 * 64 * 4); 39 | 40 | void* gpuFont = gpuAlloc(ctrcommon_font_bin_size); 41 | memcpy(gpuFont, ctrcommon_font_bin, ctrcommon_font_bin_size); 42 | gpuCreateTexture(&fontTexture); 43 | gpuTextureData(fontTexture, gpuFont, 128, 128, PIXEL_RGBA8, TEXTURE_MIN_FILTER(FILTER_NEAREST) | TEXTURE_MAG_FILTER(FILTER_NEAREST)); 44 | gpuFree(gpuFont); 45 | 46 | float identity[16]; 47 | gputIdentityMatrix(identity); 48 | gputProjection(identity); 49 | gputModelView(identity); 50 | } 51 | 52 | void gputCleanup() { 53 | if(defaultShader != 0) { 54 | gpuFreeShader(defaultShader); 55 | defaultShader = 0; 56 | } 57 | 58 | if(stringVbo != 0) { 59 | gpuFreeVbo(stringVbo); 60 | stringVbo = 0; 61 | } 62 | 63 | if(fontTexture != 0) { 64 | gpuFreeTexture(fontTexture); 65 | fontTexture = 0; 66 | } 67 | } 68 | 69 | void gputUseDefaultShader() { 70 | gpuUseShader(defaultShader); 71 | } 72 | 73 | void gputMultMatrix4(float* out, const float* m1, const float* m2) { 74 | if(out == NULL || m1 == NULL || m2 == NULL) { 75 | return; 76 | } 77 | 78 | for(u32 x1 = 0; x1 < 4; x1++) { 79 | for(u32 y2 = 0; y2 < 4; y2++) { 80 | out[y2 * 4 + x1] = 0; 81 | for(u32 y1 = 0; y1 < 4; y1++) { 82 | out[y2 * 4 + x1] += m1[y1 * 4 + x1] * m2[y2 * 4 + y1]; 83 | } 84 | } 85 | } 86 | } 87 | 88 | void gputIdentityMatrix(float *out) { 89 | if(out == NULL) { 90 | return; 91 | } 92 | 93 | memset(out, 0x00, 16 * sizeof(float)); 94 | out[0] = 1.0f; 95 | out[5] = 1.0f; 96 | out[10] = 1.0f; 97 | out[15] = 1.0f; 98 | } 99 | 100 | void gputOrthoMatrix(float* out, float left, float right, float bottom, float top, float near, float far) { 101 | float orthoMatrix[16]; 102 | 103 | orthoMatrix[0] = 2.0f / (right - left); 104 | orthoMatrix[1] = 0.0f; 105 | orthoMatrix[2] = 0.0f; 106 | orthoMatrix[3] = -((right + left) / (right - left)); 107 | 108 | orthoMatrix[4] = 0.0f; 109 | orthoMatrix[5] = 2.0f / (top - bottom); 110 | orthoMatrix[6] = 0.0f; 111 | orthoMatrix[7] = -((top + bottom) / (top - bottom)); 112 | 113 | orthoMatrix[8] = 0.0f; 114 | orthoMatrix[9] = 0.0f; 115 | orthoMatrix[10] = 2.0f / (far - near); 116 | orthoMatrix[11] = -((far + near) / (far - near)); 117 | 118 | orthoMatrix[12] = 0.0f; 119 | orthoMatrix[13] = 0.0f; 120 | orthoMatrix[14] = 0.0f; 121 | orthoMatrix[15] = 1.0f; 122 | 123 | float correction[16]; 124 | gputRotationMatrixZ(correction, (float) M_PI / 2.0f); 125 | 126 | gputMultMatrix4(out, orthoMatrix, correction); 127 | } 128 | 129 | void gputPerspectiveMatrix(float* out, float fovy, float aspect, float near, float far) { 130 | float top = near * (float) tan(fovy / 2); 131 | float right = top * aspect; 132 | 133 | float projectionMatrix[16]; 134 | 135 | projectionMatrix[0] = near / right; 136 | projectionMatrix[1] = 0.0f; 137 | projectionMatrix[2] = 0.0f; 138 | projectionMatrix[3] = 0.0f; 139 | 140 | projectionMatrix[4] = 0.0f; 141 | projectionMatrix[5] = near / top; 142 | projectionMatrix[6] = 0.0f; 143 | projectionMatrix[7] = 0.0f; 144 | 145 | projectionMatrix[8] = 0.0f; 146 | projectionMatrix[9] = 0.0f; 147 | projectionMatrix[10] = -(far + near) / (far - near); 148 | projectionMatrix[11] = -2.0f * (far * near) / (far - near); 149 | 150 | projectionMatrix[12] = 0.0f; 151 | projectionMatrix[13] = 0.0f; 152 | projectionMatrix[14] = -1.0f; 153 | projectionMatrix[15] = 0.0f; 154 | 155 | float correction[16]; 156 | gputIdentityMatrix(correction); 157 | correction[10] = 0.5f; 158 | correction[11] = -0.5f; 159 | 160 | gputMultMatrix4(out, correction, projectionMatrix); 161 | } 162 | 163 | void gputTranslationMatrix(float* out, float x, float y, float z) { 164 | if(out == NULL) { 165 | return; 166 | } 167 | 168 | gputIdentityMatrix(out); 169 | out[3] = x; 170 | out[7] = y; 171 | out[11] = z; 172 | } 173 | 174 | void gputRotationMatrixX(float* out, float rotation) { 175 | if(out == NULL) { 176 | return; 177 | } 178 | 179 | memset(out, 0x00, 16 * sizeof(float)); 180 | 181 | out[0] = 1.0f; 182 | out[5] = (float) cos(rotation); 183 | out[6] = (float) sin(rotation); 184 | out[9] = (float) -sin(rotation); 185 | out[10] = (float) cos(rotation); 186 | out[15] = 1.0f; 187 | } 188 | 189 | void gputRotationMatrixY(float* out, float rotation) { 190 | if(out == NULL) { 191 | return; 192 | } 193 | 194 | memset(out, 0x00, 16 * sizeof(float)); 195 | 196 | out[0] = (float) cos(rotation); 197 | out[2] = (float) sin(rotation); 198 | out[5] = 1.0f; 199 | out[8] = (float) -sin(rotation); 200 | out[10] = (float) cos(rotation); 201 | out[15] = 1.0f; 202 | } 203 | 204 | void gputRotationMatrixZ(float* out, float rotation) { 205 | if(out == NULL) { 206 | return; 207 | } 208 | 209 | memset(out, 0x00, 16 * sizeof(float)); 210 | 211 | out[0] = (float) cos(rotation); 212 | out[1] = (float) sin(rotation); 213 | out[4] = (float) -sin(rotation); 214 | out[5] = (float) cos(rotation); 215 | out[10] = 1.0f; 216 | out[15] = 1.0f; 217 | } 218 | 219 | void gputScaleMatrix(float *matrix, float x, float y, float z) { 220 | matrix[0] *= x; 221 | matrix[4] *= x; 222 | matrix[8] *= x; 223 | matrix[12] *= x; 224 | 225 | matrix[1] *= y; 226 | matrix[5] *= y; 227 | matrix[9] *= y; 228 | matrix[13] *= y; 229 | 230 | matrix[2] *= z; 231 | matrix[6] *= z; 232 | matrix[10] *= z; 233 | matrix[14] *= z; 234 | } 235 | 236 | void gputPushProjection() { 237 | float* old = (float*) malloc(16 * sizeof(float)); 238 | memcpy(old, projection, 16 * sizeof(float)); 239 | projectionStack.push(old); 240 | } 241 | 242 | void gputPopProjection() { 243 | if(projectionStack.empty()) { 244 | return; 245 | } 246 | 247 | float* old = projectionStack.top(); 248 | projectionStack.pop(); 249 | gputProjection(old); 250 | free(old); 251 | } 252 | 253 | float* gputGetProjection() { 254 | return projection; 255 | } 256 | 257 | void gputProjection(float* matrix) { 258 | if(matrix == NULL) { 259 | return; 260 | } 261 | 262 | memcpy(projection, matrix, 16 * sizeof(float)); 263 | gpuSetUniform(defaultShader, VERTEX_SHADER, "projection", projection, 4); 264 | } 265 | 266 | void gputOrtho(float left, float right, float bottom, float top, float near, float far) { 267 | float orthoMatrix[16]; 268 | gputOrthoMatrix(orthoMatrix, left, right, bottom, top, near, far); 269 | gputProjection(orthoMatrix); 270 | } 271 | 272 | void gputPerspective(float fovy, float aspect, float near, float far) { 273 | float perspectiveMatrix[16]; 274 | gputPerspectiveMatrix(perspectiveMatrix, fovy, aspect, near, far); 275 | gputProjection(perspectiveMatrix); 276 | } 277 | 278 | void gputPushModelView() { 279 | float* old = (float*) malloc(16 * sizeof(float)); 280 | memcpy(old, modelview, 16 * sizeof(float)); 281 | modelviewStack.push(old); 282 | } 283 | 284 | void gputPopModelView() { 285 | if(modelviewStack.empty()) { 286 | return; 287 | } 288 | 289 | float* old = modelviewStack.top(); 290 | modelviewStack.pop(); 291 | gputModelView(old); 292 | free(old); 293 | } 294 | 295 | float* gputGetModelView() { 296 | return modelview; 297 | } 298 | 299 | void gputModelView(float* matrix) { 300 | if(matrix == NULL) { 301 | return; 302 | } 303 | 304 | memcpy(modelview, matrix, 16 * sizeof(float)); 305 | gpuSetUniform(defaultShader, VERTEX_SHADER, "modelview", modelview, 4); 306 | } 307 | 308 | void gputTranslate(float x, float y, float z) { 309 | float translationMatrix[16]; 310 | gputTranslationMatrix(translationMatrix, x, y, z); 311 | 312 | float resultMatrix[16]; 313 | gputMultMatrix4(resultMatrix, modelview, translationMatrix); 314 | gputModelView(resultMatrix); 315 | } 316 | 317 | void gputRotateX(float rotation) { 318 | float rotationMatrix[16]; 319 | gputRotationMatrixX(rotationMatrix, rotation); 320 | 321 | float resultMatrix[16]; 322 | gputMultMatrix4(resultMatrix, modelview, rotationMatrix); 323 | gputModelView(resultMatrix); 324 | } 325 | 326 | void gputRotateY(float rotation) { 327 | float rotationMatrix[16]; 328 | gputRotationMatrixY(rotationMatrix, rotation); 329 | 330 | float resultMatrix[16]; 331 | gputMultMatrix4(resultMatrix, modelview, rotationMatrix); 332 | gputModelView(resultMatrix); 333 | } 334 | 335 | void gputRotateZ(float rotation) { 336 | float rotationMatrix[16]; 337 | gputRotationMatrixZ(rotationMatrix, rotation); 338 | 339 | float resultMatrix[16]; 340 | gputMultMatrix4(resultMatrix, modelview, rotationMatrix); 341 | gputModelView(resultMatrix); 342 | } 343 | 344 | void gputRotate(float x, float y, float z) { 345 | float tempMatrix[16]; 346 | float tempMatrix2[16]; 347 | float tempMatrix3[16]; 348 | 349 | gputRotationMatrixX(tempMatrix, x); 350 | gputRotationMatrixY(tempMatrix2, y); 351 | gputMultMatrix4(tempMatrix3, tempMatrix, tempMatrix2); 352 | 353 | gputRotationMatrixZ(tempMatrix2, z); 354 | gputMultMatrix4(tempMatrix, tempMatrix3, tempMatrix2); 355 | 356 | gputMultMatrix4(tempMatrix2, modelview, tempMatrix); 357 | gputModelView(tempMatrix2); 358 | } 359 | 360 | void gputScale(float x, float y, float z) { 361 | gputScaleMatrix(modelview, x, y, z); 362 | gputModelView(modelview); 363 | } 364 | 365 | float gputGetStringWidth(const std::string str, float charWidth) { 366 | u32 len = str.length(); 367 | if(len == 0) { 368 | return 0; 369 | } 370 | 371 | u32 longestLine = 0; 372 | u32 currLength = 0; 373 | for(u32 i = 0; i < len; i++) { 374 | if(str[i] == '\n') { 375 | if(currLength > longestLine) { 376 | longestLine = currLength; 377 | } 378 | 379 | currLength = 0; 380 | continue; 381 | } 382 | 383 | currLength++; 384 | } 385 | 386 | if(currLength > longestLine) { 387 | longestLine = currLength; 388 | } 389 | 390 | return (int) (longestLine * charWidth); 391 | } 392 | 393 | float gputGetStringHeight(const std::string str, float charHeight) { 394 | u32 len = str.length(); 395 | if(len == 0) { 396 | return 0; 397 | } 398 | 399 | u32 lines = 1; 400 | for(u32 i = 0; i < len; i++) { 401 | if(str[i] == '\n') { 402 | lines++; 403 | } 404 | } 405 | 406 | return (int) (lines * charHeight); 407 | } 408 | 409 | void gputDrawString(const std::string str, float x, float y, float charWidth, float charHeight, u8 red, u8 green, u8 blue, u8 alpha) { 410 | const u32 len = str.length(); 411 | if(len == 0) { 412 | return; 413 | } 414 | 415 | static const float charSize = 8.0f / 128.0f; 416 | 417 | const float r = (float) red / 255.0f; 418 | const float g = (float) green / 255.0f; 419 | const float b = (float) blue / 255.0f; 420 | const float a = (float) alpha / 255.0f; 421 | 422 | gpuVboDataInfo(stringVbo, len * 6, PRIM_TRIANGLES); 423 | float* tempVboData = (float*) gpuGetVboData(stringVbo); 424 | 425 | float cx = x; 426 | float cy = y + gputGetStringHeight(str, charHeight) - charHeight; 427 | for(u32 i = 0; i < len; i++) { 428 | char c = str[i]; 429 | if(c == '\n') { 430 | memset(tempVboData + (i * 6 * 9), 0, 6 * 9 * sizeof(float)); 431 | 432 | cx = x; 433 | cy -= charHeight; 434 | continue; 435 | } 436 | 437 | const float texX1 = (c % 16) * charSize; 438 | const float texY1 = 1.0f - ((c / 16 + 1) * charSize); 439 | const float texX2 = texX1 + charSize; 440 | const float texY2 = texY1 + charSize; 441 | 442 | const float vboData[] = { 443 | cx, cy, -0.1f, texX1, texY1, r, g, b, a, 444 | cx + charWidth, cy, -0.1f, texX2, texY1, r, g, b, a, 445 | cx + charWidth, cy + charHeight, -0.1f, texX2, texY2, r, g, b, a, 446 | cx + charWidth, cy + charHeight, -0.1f, texX2, texY2, r, g, b, a, 447 | cx, cy + charHeight, -0.1f, texX1, texY2, r, g, b, a, 448 | cx, cy, -0.1f, texX1, texY1, r, g, b, a 449 | }; 450 | 451 | memcpy(tempVboData + (i * 6 * 9), vboData, sizeof(vboData)); 452 | cx += charWidth; 453 | } 454 | 455 | gpuBindTexture(TEXUNIT0, fontTexture); 456 | gpuDrawVbo(stringVbo); 457 | 458 | // Flush the GPU command buffer so we can safely reuse the VBO. 459 | gpuFlush(); 460 | } 461 | 462 | void gputTakeScreenshot() { 463 | u32 headerSize = 0x36; 464 | u32 imageSize = 400 * 480 * 3; 465 | 466 | u8* header = (u8*) malloc(headerSize); 467 | memset(header, 0, headerSize); 468 | 469 | *(u16*) &header[0x0] = 0x4D42; 470 | *(u32*) &header[0x2] = headerSize + imageSize; 471 | *(u32*) &header[0xA] = headerSize; 472 | *(u32*) &header[0xE] = 0x28; 473 | *(u32*) &header[0x12] = 400; 474 | *(u32*) &header[0x16] = 480; 475 | *(u32*) &header[0x1A] = 0x00180001; 476 | *(u32*) &header[0x22] = imageSize; 477 | 478 | u8* image = (u8*) malloc(imageSize); 479 | memset(image, 0, imageSize); 480 | 481 | if(gfxGetScreenFormat(GFX_TOP) == GSP_BGR8_OES) { 482 | u8* top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); 483 | for(u32 x = 0; x < 400; x++) { 484 | for(u32 y = 0; y < 240; y++) { 485 | u8* src = &top[((240 - y - 1) + x * 240) * 3]; 486 | u8* dst = &image[((479 - y) * 400 + x) * 3]; 487 | 488 | *(u16*) dst = *(u16*) src; 489 | dst[2] = src[2]; 490 | } 491 | } 492 | } 493 | 494 | if(gfxGetScreenFormat(GFX_BOTTOM) == GSP_BGR8_OES) { 495 | u8* bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); 496 | for(u32 x = 0; x < 320; x++) { 497 | for(u32 y = 0; y < 240; y++) { 498 | u8* src = &bottom[((240 - y - 1) + x * 240) * 3]; 499 | u8* dst = &image[((479 - (y + 240)) * 400 + (x + 40)) * 3]; 500 | 501 | *(u16*) dst = *(u16*) src; 502 | dst[2] = src[2]; 503 | } 504 | } 505 | } 506 | 507 | std::stringstream fileStream; 508 | fileStream << "/screenshot_" << platformGetTime() << ".bmp"; 509 | std::string file = fileStream.str(); 510 | 511 | FILE* fd = fopen(file.c_str(), "wb"); 512 | if(fd) { 513 | fwrite(header, 1, headerSize, fd); 514 | fwrite(image, 1, imageSize, fd); 515 | fclose(fd); 516 | } 517 | 518 | free(header); 519 | free(image); 520 | } -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/platform.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/platform.hpp" 2 | 3 | #include "service.hpp" 4 | #include "../libkhax/khax.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include <3ds.h> 14 | 15 | #include 16 | 17 | static bool hasError = false; 18 | static Error currentError = {0}; 19 | 20 | extern bool gpuInit(); 21 | extern void gpuCleanup(); 22 | 23 | extern void uiInit(); 24 | extern void uiCleanup(); 25 | 26 | bool platformInit() { 27 | if(gpuInit()) { 28 | uiInit(); 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | void platformCleanup() { 36 | uiCleanup(); 37 | gpuCleanup(); 38 | serviceCleanup(); 39 | } 40 | 41 | bool platformIsRunning() { 42 | return aptMainLoop(); 43 | } 44 | 45 | bool platformIsNinjhax() { 46 | Result result = hbInit(); 47 | if(result == 0) { 48 | hbExit(); 49 | } 50 | 51 | return result == 0; 52 | } 53 | 54 | bool platformExecuteKernel(s32 (*func)()) { 55 | if(!serviceRequire("kernel")) { 56 | return false; 57 | } 58 | 59 | svcBackdoor(func); 60 | return true; 61 | } 62 | 63 | u32 platformGetDeviceId() { 64 | if(!serviceRequire("am")) { 65 | return 0; 66 | } 67 | 68 | u32 deviceId; 69 | Result result = AM_GetDeviceId(&deviceId); 70 | if(result != 0) { 71 | platformSetError(serviceParseError((u32) result)); 72 | return 0; 73 | } 74 | 75 | return deviceId; 76 | } 77 | 78 | bool platformIsWifiConnected() { 79 | if(!serviceRequire("ac")) { 80 | return false; 81 | } 82 | 83 | u32 status; 84 | Result result = ACU_GetWifiStatus(NULL, &status); 85 | if(result != 0) { 86 | platformSetError(serviceParseError((u32) result)); 87 | return false; 88 | } 89 | 90 | return status != 0; 91 | } 92 | 93 | bool platformWaitForInternet() { 94 | if(!serviceRequire("ac")) { 95 | return false; 96 | } 97 | 98 | Result result = ACU_WaitInternetConnection(); 99 | if(result != 0) { 100 | platformSetError(serviceParseError((u32) result)); 101 | } 102 | 103 | return result == 0; 104 | } 105 | 106 | u8 platformGetWifiLevel() { 107 | return platformIsWifiConnected() ? osGetWifiStrength() : (u8) 0; 108 | } 109 | 110 | bool platformIsBatteryCharging() { 111 | if(!serviceRequire("ptm")) { 112 | return false; 113 | } 114 | 115 | u8 charging; 116 | Result result = PTMU_GetBatteryChargeState(NULL, &charging); 117 | if(result != 0) { 118 | platformSetError(serviceParseError((u32) result)); 119 | return false; 120 | } 121 | 122 | return charging != 0; 123 | } 124 | 125 | u8 platformGetBatteryLevel() { 126 | if(!serviceRequire("ptm")) { 127 | return 0; 128 | } 129 | 130 | u8 batteryLevel; 131 | Result result = PTMU_GetBatteryLevel(NULL, &batteryLevel); 132 | if(result != 0) { 133 | platformSetError(serviceParseError((u32) result)); 134 | return 0; 135 | } 136 | 137 | return batteryLevel; 138 | } 139 | 140 | u64 platformGetTime() { 141 | return osGetTime(); 142 | } 143 | 144 | void platformDelay(int ms) { 145 | svcSleepThread(ms * 1000000); 146 | } 147 | 148 | void platformPrintf(const char* format, ...) { 149 | char buffer[256]; 150 | 151 | va_list args; 152 | va_start(args, format); 153 | vsnprintf(buffer, 256, format, args); 154 | va_end(args); 155 | 156 | svcOutputDebugString(buffer, strlen(buffer)); 157 | } 158 | 159 | bool platformHasError() { 160 | return hasError; 161 | } 162 | 163 | Error platformGetError() { 164 | Error error = currentError; 165 | if(hasError) { 166 | hasError = false; 167 | currentError = {0}; 168 | } 169 | 170 | return error; 171 | } 172 | 173 | void platformSetError(Error error) { 174 | hasError = true; 175 | currentError = error; 176 | } 177 | 178 | std::string platformGetErrorString(Error error) { 179 | std::stringstream result; 180 | 181 | result << "Raw Error: 0x" << std::hex << error.raw << "\n"; 182 | 183 | result << "Module: "; 184 | switch(error.module) { 185 | case MODULE_COMMON: 186 | result << "MODULE_COMMON"; 187 | break; 188 | case MODULE_NN_KERNEL: 189 | result << "MODULE_NN_KERNEL"; 190 | break; 191 | case MODULE_NN_UTIL: 192 | result << "MODULE_NN_UTIL"; 193 | break; 194 | case MODULE_NN_FILE_SERVER: 195 | result << "MODULE_NN_FILE_SERVER"; 196 | break; 197 | case MODULE_NN_LOADER_SERVER: 198 | result << "MODULE_NN_LOADER_SERVER"; 199 | break; 200 | case MODULE_NN_TCB: 201 | result << "MODULE_NN_TCB"; 202 | break; 203 | case MODULE_NN_OS: 204 | result << "MODULE_NN_OS"; 205 | break; 206 | case MODULE_NN_DBG: 207 | result << "MODULE_NN_DBG"; 208 | break; 209 | case MODULE_NN_DMNT: 210 | result << "MODULE_NN_DMNT"; 211 | break; 212 | case MODULE_NN_PDN: 213 | result << "MODULE_NN_PDN"; 214 | break; 215 | case MODULE_NN_GX: 216 | result << "MODULE_NN_GX"; 217 | break; 218 | case MODULE_NN_I2C: 219 | result << "MODULE_NN_I2C"; 220 | break; 221 | case MODULE_NN_GPIO: 222 | result << "MODULE_NN_GPIO"; 223 | break; 224 | case MODULE_NN_DD: 225 | result << "MODULE_NN_DD"; 226 | break; 227 | case MODULE_NN_CODEC: 228 | result << "MODULE_NN_CODEC"; 229 | break; 230 | case MODULE_NN_SPI: 231 | result << "MODULE_NN_SPI"; 232 | break; 233 | case MODULE_NN_PXI: 234 | result << "MODULE_NN_PXI"; 235 | break; 236 | case MODULE_NN_FS: 237 | result << "MODULE_NN_FS"; 238 | break; 239 | case MODULE_NN_DI: 240 | result << "MODULE_NN_DI"; 241 | break; 242 | case MODULE_NN_HID: 243 | result << "MODULE_NN_HID"; 244 | break; 245 | case MODULE_NN_CAMERA: 246 | result << "MODULE_NN_CAMERA"; 247 | break; 248 | case MODULE_NN_PI: 249 | result << "MODULE_NN_PI"; 250 | break; 251 | case MODULE_NN_PM: 252 | result << "MODULE_NN_PM"; 253 | break; 254 | case MODULE_NN_PMLOW: 255 | result << "MODULE_NN_PMLOW"; 256 | break; 257 | case MODULE_NN_FSI: 258 | result << "MODULE_NN_FSI"; 259 | break; 260 | case MODULE_NN_SRV: 261 | result << "MODULE_NN_SRV"; 262 | break; 263 | case MODULE_NN_NDM: 264 | result << "MODULE_NN_NDM"; 265 | break; 266 | case MODULE_NN_NWM: 267 | result << "MODULE_NN_NWM"; 268 | break; 269 | case MODULE_NN_SOCKET: 270 | result << "MODULE_NN_SOCKET"; 271 | break; 272 | case MODULE_NN_LDR: 273 | result << "MODULE_NN_LDR"; 274 | break; 275 | case MODULE_NN_ACC: 276 | result << "MODULE_NN_ACC"; 277 | break; 278 | case MODULE_NN_ROMFS: 279 | result << "MODULE_NN_ROMFS"; 280 | break; 281 | case MODULE_NN_AM: 282 | result << "MODULE_NN_AM"; 283 | break; 284 | case MODULE_NN_HIO: 285 | result << "MODULE_NN_HIO"; 286 | break; 287 | case MODULE_NN_UPDATER: 288 | result << "MODULE_NN_UPDATER"; 289 | break; 290 | case MODULE_NN_MIC: 291 | result << "MODULE_NN_MIC"; 292 | break; 293 | case MODULE_NN_FND: 294 | result << "MODULE_NN_FND"; 295 | break; 296 | case MODULE_NN_MP: 297 | result << "MODULE_NN_MP"; 298 | break; 299 | case MODULE_NN_MPWL: 300 | result << "MODULE_NN_MPWL"; 301 | break; 302 | case MODULE_NN_AC: 303 | result << "MODULE_NN_AC"; 304 | break; 305 | case MODULE_NN_HTTP: 306 | result << "MODULE_NN_HTTP"; 307 | break; 308 | case MODULE_NN_DSP: 309 | result << "MODULE_NN_DSP"; 310 | break; 311 | case MODULE_NN_SND: 312 | result << "MODULE_NN_SND"; 313 | break; 314 | case MODULE_NN_DLP: 315 | result << "MODULE_NN_DLP"; 316 | break; 317 | case MODULE_NN_HIOLOW: 318 | result << "MODULE_NN_HIOLOW"; 319 | break; 320 | case MODULE_NN_CSND: 321 | result << "MODULE_NN_CSND"; 322 | break; 323 | case MODULE_NN_SSL: 324 | result << "MODULE_NN_SSL"; 325 | break; 326 | case MODULE_NN_AMLOW: 327 | result << "MODULE_NN_AMLOW"; 328 | break; 329 | case MODULE_NN_NEX: 330 | result << "MODULE_NN_NEX"; 331 | break; 332 | case MODULE_NN_FRIENDS: 333 | result << "MODULE_NN_FRIENDS"; 334 | break; 335 | case MODULE_NN_RDT: 336 | result << "MODULE_NN_RDT"; 337 | break; 338 | case MODULE_NN_APPLET: 339 | result << "MODULE_NN_APPLET"; 340 | break; 341 | case MODULE_NN_NIM: 342 | result << "MODULE_NN_NIM"; 343 | break; 344 | case MODULE_NN_PTM: 345 | result << "MODULE_NN_PTM"; 346 | break; 347 | case MODULE_NN_MIDI: 348 | result << "MODULE_NN_MIDI"; 349 | break; 350 | case MODULE_NN_MC: 351 | result << "MODULE_NN_MC"; 352 | break; 353 | case MODULE_NN_SWC: 354 | result << "MODULE_NN_SWC"; 355 | break; 356 | case MODULE_NN_FATFS: 357 | result << "MODULE_NN_FATFS"; 358 | break; 359 | case MODULE_NN_NGC: 360 | result << "MODULE_NN_NGC"; 361 | break; 362 | case MODULE_NN_CARD: 363 | result << "MODULE_NN_CARD"; 364 | break; 365 | case MODULE_NN_CARDNOR: 366 | result << "MODULE_NN_CARDNOR"; 367 | break; 368 | case MODULE_NN_SDMC: 369 | result << "MODULE_NN_SDMC"; 370 | break; 371 | case MODULE_NN_BOSS: 372 | result << "MODULE_NN_BOSS"; 373 | break; 374 | case MODULE_NN_DBM: 375 | result << "MODULE_NN_DBM"; 376 | break; 377 | case MODULE_NN_CONFIG: 378 | result << "MODULE_NN_CONFIG"; 379 | break; 380 | case MODULE_NN_PS: 381 | result << "MODULE_NN_PS"; 382 | break; 383 | case MODULE_NN_CEC: 384 | result << "MODULE_NN_CEC"; 385 | break; 386 | case MODULE_NN_IR: 387 | result << "MODULE_NN_IR"; 388 | break; 389 | case MODULE_NN_UDS: 390 | result << "MODULE_NN_UDS"; 391 | break; 392 | case MODULE_NN_PL: 393 | result << "MODULE_NN_PL"; 394 | break; 395 | case MODULE_NN_CUP: 396 | result << "MODULE_NN_CUP"; 397 | break; 398 | case MODULE_NN_GYROSCOPE: 399 | result << "MODULE_NN_GYROSCOPE"; 400 | break; 401 | case MODULE_NN_MCU: 402 | result << "MODULE_NN_MCU"; 403 | break; 404 | case MODULE_NN_NS: 405 | result << "MODULE_NN_NS"; 406 | break; 407 | case MODULE_NN_NEWS: 408 | result << "MODULE_NN_NEWS"; 409 | break; 410 | case MODULE_NN_RO: 411 | result << "MODULE_NN_RO"; 412 | break; 413 | case MODULE_NN_GD: 414 | result << "MODULE_NN_GD"; 415 | break; 416 | case MODULE_NN_CARDSPI: 417 | result << "MODULE_NN_CARDSPI"; 418 | break; 419 | case MODULE_NN_EC: 420 | result << "MODULE_NN_EC"; 421 | break; 422 | case MODULE_NN_WEBBRS: 423 | result << "MODULE_NN_WEBBRS"; 424 | break; 425 | case MODULE_NN_TEST: 426 | result << "MODULE_NN_TEST"; 427 | break; 428 | case MODULE_NN_ENC: 429 | result << "MODULE_NN_ENC"; 430 | break; 431 | case MODULE_NN_PIA: 432 | result << "MODULE_NN_PIA"; 433 | break; 434 | case MODULE_NN_MVD: 435 | result << "MODULE_NN_MVD"; 436 | break; 437 | case MODULE_NN_QTM: 438 | result << "MODULE_NN_QTM"; 439 | break; 440 | case MODULE_APPLICATION: 441 | result << "MODULE_APPLICATION"; 442 | break; 443 | case MODULE_INVALID_RESULT_VALUE: 444 | result << "MODULE_INVALID_RESULT_VALUE"; 445 | break; 446 | default: 447 | result << ""; 448 | break; 449 | } 450 | 451 | result << " (0x" << std::hex << error.module << ")" << "\n"; 452 | 453 | result << "Level: "; 454 | switch(error.level) { 455 | case LEVEL_SUCCESS: 456 | result << "LEVEL_SUCCESS"; 457 | break; 458 | case LEVEL_INFO: 459 | result << "LEVEL_INFO"; 460 | break; 461 | case LEVEL_STATUS: 462 | result << "LEVEL_STATUS"; 463 | break; 464 | case LEVEL_TEMPORARY: 465 | result << "LEVEL_TEMPORARY"; 466 | break; 467 | case LEVEL_PERMANENT: 468 | result << "LEVEL_PERMANENT"; 469 | break; 470 | case LEVEL_USAGE: 471 | result << "LEVEL_USAGE"; 472 | break; 473 | case LEVEL_REINIT: 474 | result << "LEVEL_REINIT"; 475 | break; 476 | case LEVEL_RESET: 477 | result << "LEVEL_RESET"; 478 | break; 479 | case LEVEL_FATAL: 480 | result << "LEVEL_FATAL"; 481 | break; 482 | default: 483 | result << ""; 484 | break; 485 | } 486 | 487 | result << " (0x" << std::hex << error.level << ")" << "\n"; 488 | 489 | result << "Summary: "; 490 | switch(error.summary) { 491 | case SUMMARY_SUCCESS: 492 | result << "SUMMARY_SUCCESS"; 493 | break; 494 | case SUMMARY_NOTHING_HAPPENED: 495 | result << "SUMMARY_NOTHING_HAPPENED"; 496 | break; 497 | case SUMMARY_WOULD_BLOCK: 498 | result << "SUMMARY_WOULD_BLOCK"; 499 | break; 500 | case SUMMARY_OUT_OF_RESOURCE: 501 | result << "SUMMARY_OUT_OF_RESOURCE"; 502 | break; 503 | case SUMMARY_NOT_FOUND: 504 | result << "SUMMARY_NOT_FOUND"; 505 | break; 506 | case SUMMARY_INVALID_STATE: 507 | result << "SUMMARY_INVALID_STATE"; 508 | break; 509 | case SUMMARY_NOT_SUPPORTED: 510 | result << "SUMMARY_NOT_SUPPORTED"; 511 | break; 512 | case SUMMARY_INVALID_ARGUMENT: 513 | result << "SUMMARY_INVALID_ARGUMENT"; 514 | break; 515 | case SUMMARY_WRONG_ARGUMENT: 516 | result << "SUMMARY_WRONG_ARGUMENT"; 517 | break; 518 | case SUMMARY_CANCELED: 519 | result << "SUMMARY_CANCELED"; 520 | break; 521 | case SUMMARY_STATUS_CHANGED: 522 | result << "SUMMARY_STATUS_CHANGED"; 523 | break; 524 | case SUMMARY_INTERNAL: 525 | result << "SUMMARY_INTERNAL"; 526 | break; 527 | case SUMMARY_INVALID_RESULT_VALUE: 528 | result << "SUMMARY_INVALID_RESULT_VALUE"; 529 | break; 530 | default: 531 | result << ""; 532 | break; 533 | } 534 | 535 | result << " (0x" << std::hex << error.summary << ")" << "\n"; 536 | 537 | result << "Description: "; 538 | switch(error.description) { 539 | case DESCRIPTION_SUCCESS: 540 | result << "DESCRIPTION_SUCCESS"; 541 | break; 542 | case DESCRIPTION_INVALID_MEMORY_PERMISSIONS: 543 | result << "DESCRIPTION_INVALID_MEMORY_PERMISSIONS"; 544 | break; 545 | case DESCRIPTION_INVALID_TICKET_VERSION: 546 | result << "DESCRIPTION_INVALID_TICKET_VERSION"; 547 | break; 548 | case DESCRIPTION_STRING_TOO_BIG: 549 | result << "DESCRIPTION_STRING_TOO_BIG"; 550 | break; 551 | case DESCRIPTION_ACCESS_DENIED: 552 | result << "DESCRIPTION_ACCESS_DENIED"; 553 | break; 554 | case DESCRIPTION_STRING_TOO_SMALL: 555 | result << "DESCRIPTION_STRING_TOO_SMALL"; 556 | break; 557 | case DESCRIPTION_CAMERA_BUSY: 558 | result << "DESCRIPTION_CAMERA_BUSY"; 559 | break; 560 | case DESCRIPTION_NOT_ENOUGH_MEMORY: 561 | result << "DESCRIPTION_NOT_ENOUGH_MEMORY"; 562 | break; 563 | case DESCRIPTION_SESSION_CLOSED_BY_REMOTE: 564 | result << "DESCRIPTION_SESSION_CLOSED_BY_REMOTE"; 565 | break; 566 | case DESCRIPTION_INVALID_NCCH: 567 | result << "DESCRIPTION_INVALID_NCCH"; 568 | break; 569 | case DESCRIPTION_INVALID_TITLE_VERSION: 570 | result << "DESCRIPTION_INVALID_TITLE_VERSION"; 571 | break; 572 | case DESCRIPTION_DATABASE_DOES_NOT_EXIST: 573 | result << "DESCRIPTION_DATABASE_DOES_NOT_EXIST"; 574 | break; 575 | case DESCRIPTION_TRIED_TO_UNINSTALL_SYSTEM_APP: 576 | result << "DESCRIPTION_TRIED_TO_UNINSTALL_SYSTEM_APP"; 577 | break; 578 | case DESCRIPTION_ARCHIVE_NOT_MOUNTED: 579 | result << "DESCRIPTION_ARCHIVE_NOT_MOUNTED"; 580 | break; 581 | case DESCRIPTION_REQUEST_TIMED_OUT: 582 | result << "DESCRIPTION_REQUEST_TIMED_OUT"; 583 | break; 584 | case DESCRIPTION_INVALID_SIGNATURE: 585 | result << "DESCRIPTION_INVALID_SIGNATURE"; 586 | break; 587 | case DESCRIPTION_TITLE_NOT_FOUND: 588 | result << "DESCRIPTION_TITLE_NOT_FOUND"; 589 | break; 590 | case DESCRIPTION_GAMECARD_NOT_INSERTED: 591 | result << "DESCRIPTION_GAMECARD_NOT_INSERTED"; 592 | break; 593 | case DESCRIPTION_INVALID_FILE_OPEN_FLAGS: 594 | result << "DESCRIPTION_INVALID_FILE_OPEN_FLAGS"; 595 | break; 596 | case DESCRIPTION_INVALID_CONFIGURATION: 597 | result << "DESCRIPTION_INVALID_CONFIGURATION"; 598 | break; 599 | case DESCRIPTION_NCCH_HASH_CHECK_FAILED: 600 | result << "DESCRIPTION_NCCH_HASH_CHECK_FAILED"; 601 | break; 602 | case DESCRIPTION_AES_VERIFICATION_FAILED: 603 | result << "DESCRIPTION_AES_VERIFICATION_FAILED"; 604 | break; 605 | case DESCRIPTION_INVALID_DATABASE: 606 | result << "DESCRIPTION_INVALID_DATABASE"; 607 | break; 608 | case DESCRIPTION_SAVE_HASH_CHECK_FAILED: 609 | result << "DESCRIPTION_SAVE_HASH_CHECK_FAILED"; 610 | break; 611 | case DESCRIPTION_COMMAND_PERMISSION_DENIED: 612 | result << "DESCRIPTION_COMMAND_PERMISSION_DENIED"; 613 | break; 614 | case DESCRIPTION_INVALID_PATH: 615 | result << "DESCRIPTION_INVALID_PATH"; 616 | break; 617 | case DESCRIPTION_INCORRECT_READ_SIZE: 618 | result << "DESCRIPTION_INCORRECT_READ_SIZE"; 619 | break; 620 | case DESCRIPTION_INVALID_SELECTION: 621 | result << "DESCRIPTION_INVALID_SELECTION"; 622 | break; 623 | case DESCRIPTION_TOO_LARGE: 624 | result << "DESCRIPTION_TOO_LARGE"; 625 | break; 626 | case DESCRIPTION_NOT_AUTHORIZED: 627 | result << "DESCRIPTION_NOT_AUTHORIZED"; 628 | break; 629 | case DESCRIPTION_ALREADY_DONE: 630 | result << "DESCRIPTION_ALREADY_DONE"; 631 | break; 632 | case DESCRIPTION_INVALID_SIZE: 633 | result << "DESCRIPTION_INVALID_SIZE"; 634 | break; 635 | case DESCRIPTION_INVALID_ENUM_VALUE: 636 | result << "DESCRIPTION_INVALID_ENUM_VALUE"; 637 | break; 638 | case DESCRIPTION_INVALID_COMBINATION: 639 | result << "DESCRIPTION_INVALID_COMBINATION"; 640 | break; 641 | case DESCRIPTION_NO_DATA: 642 | result << "DESCRIPTION_NO_DATA"; 643 | break; 644 | case DESCRIPTION_BUSY: 645 | result << "DESCRIPTION_BUSY"; 646 | break; 647 | case DESCRIPTION_MISALIGNED_ADDRESS: 648 | result << "DESCRIPTION_MISALIGNED_ADDRESS"; 649 | break; 650 | case DESCRIPTION_MISALIGNED_SIZE: 651 | result << "DESCRIPTION_MISALIGNED_SIZE"; 652 | break; 653 | case DESCRIPTION_OUT_OF_MEMORY: 654 | result << "DESCRIPTION_OUT_OF_MEMORY"; 655 | break; 656 | case DESCRIPTION_NOT_IMPLEMENTED: 657 | result << "DESCRIPTION_NOT_IMPLEMENTED"; 658 | break; 659 | case DESCRIPTION_INVALID_ADDRESS: 660 | result << "DESCRIPTION_INVALID_ADDRESS"; 661 | break; 662 | case DESCRIPTION_INVALID_POINTER: 663 | result << "DESCRIPTION_INVALID_POINTER"; 664 | break; 665 | case DESCRIPTION_INVALID_HANDLE: 666 | result << "DESCRIPTION_INVALID_HANDLE"; 667 | break; 668 | case DESCRIPTION_NOT_INITIALIZED: 669 | result << "DESCRIPTION_NOT_INITIALIZED"; 670 | break; 671 | case DESCRIPTION_ALREADY_INITIALIZED: 672 | result << "DESCRIPTION_ALREADY_INITIALIZED"; 673 | break; 674 | case DESCRIPTION_NOT_FOUND: 675 | result << "DESCRIPTION_NOT_FOUND"; 676 | break; 677 | case DESCRIPTION_CANCEL_REQUESTED: 678 | result << "DESCRIPTION_CANCEL_REQUESTED"; 679 | break; 680 | case DESCRIPTION_ALREADY_EXISTS: 681 | result << "DESCRIPTION_ALREADY_EXISTS"; 682 | break; 683 | case DESCRIPTION_OUT_OF_RANGE: 684 | result << "DESCRIPTION_OUT_OF_RANGE"; 685 | break; 686 | case DESCRIPTION_TIMEOUT: 687 | result << "DESCRIPTION_TIMEOUT"; 688 | break; 689 | case DESCRIPTION_INVALID_RESULT_VALUE: 690 | result << "DESCRIPTION_INVALID_RESULT_VALUE"; 691 | break; 692 | default: 693 | result << ""; 694 | break; 695 | } 696 | 697 | result << " (0x" << std::hex << error.description << ")" << "\n"; 698 | 699 | return result.str(); 700 | } -------------------------------------------------------------------------------- /lib/ctrcommon/source/ctrcommon/ui.cpp: -------------------------------------------------------------------------------- 1 | #include "ctrcommon/ui.hpp" 2 | 3 | #include "ctrcommon/app.hpp" 4 | #include "ctrcommon/fs.hpp" 5 | #include "ctrcommon/input.hpp" 6 | #include "ctrcommon/platform.hpp" 7 | #include "ctrcommon/socket.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | struct uiAlphabetize { 22 | inline bool operator()(SelectableElement a, SelectableElement b) { 23 | return strcasecmp(a.name.c_str(), b.name.c_str()) < 0; 24 | } 25 | }; 26 | 27 | u32 selectorTexture; 28 | u32 selectorVbo; 29 | 30 | void uiInit() { 31 | gpuCreateTexture(&selectorTexture); 32 | gpuTextureInfo(selectorTexture, 64, 64, PIXEL_RGBA8, TEXTURE_MIN_FILTER(FILTER_NEAREST) | TEXTURE_MAG_FILTER(FILTER_NEAREST)); 33 | memset(gpuGetTextureData(selectorTexture), 0xFF, 64 * 64 * 4); 34 | 35 | gpuCreateVbo(&selectorVbo); 36 | gpuVboAttributes(selectorVbo, ATTRIBUTE(0, 3, ATTR_FLOAT) | ATTRIBUTE(1, 2, ATTR_FLOAT) | ATTRIBUTE(2, 4, ATTR_FLOAT), 3); 37 | 38 | const float vboData[] = { 39 | 0.0f, 0.0f, -0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 40 | 320.0f, 0.0f, -0.1f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 41 | 320.0f, 12.0f, -0.1f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 42 | 320.0f, 12.0f, -0.1f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 43 | 0.0f, 12.0f, -0.1f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 44 | 0.0f, 0.0f, -0.1f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 45 | }; 46 | 47 | gpuVboData(selectorVbo, vboData, 6 * 9, PRIM_TRIANGLES); 48 | } 49 | 50 | void uiCleanup() { 51 | if(selectorTexture != 0) { 52 | gpuFreeTexture(selectorTexture); 53 | selectorTexture = 0; 54 | } 55 | 56 | if(selectorVbo != 0) { 57 | gpuFreeVbo(selectorVbo); 58 | selectorVbo = 0; 59 | } 60 | } 61 | 62 | bool uiSelect(SelectableElement* selected, std::vector elements, std::function &currElements, SelectableElement currElement, bool &elementsDirty, bool &resetCursorIfDirty)> onLoop, std::function onSelect, bool useTopScreen, bool alphabetize, bool dpadPageScroll) { 63 | int cursor = 0; 64 | int scroll = 0; 65 | 66 | u32 selectionScroll = 0; 67 | u64 selectionScrollEndTime = 0; 68 | 69 | u64 lastScrollTime = 0; 70 | 71 | bool elementsDirty = false; 72 | bool resetCursorIfDirty = true; 73 | if(alphabetize) { 74 | std::sort(elements.begin(), elements.end(), uiAlphabetize()); 75 | } 76 | 77 | Button leftScrollButton = dpadPageScroll ? BUTTON_LEFT : BUTTON_L; 78 | Button rightScrollButton = dpadPageScroll ? BUTTON_RIGHT : BUTTON_R; 79 | 80 | bool canPageUp = false; 81 | bool canPageDown = false; 82 | while(platformIsRunning()) { 83 | inputPoll(); 84 | if(inputIsPressed(BUTTON_A)) { 85 | SelectableElement select = elements.at((u32) cursor); 86 | if(onSelect == NULL || onSelect(select)) { 87 | *selected = select; 88 | return true; 89 | } 90 | } 91 | 92 | if(canPageUp) { 93 | canPageUp = !inputIsReleased(leftScrollButton); 94 | } else if(inputIsPressed(leftScrollButton)) { 95 | canPageUp = true; 96 | } 97 | 98 | if(canPageDown) { 99 | canPageDown = !inputIsReleased(rightScrollButton); 100 | } else if(inputIsPressed(rightScrollButton)) { 101 | canPageDown = true; 102 | } 103 | 104 | if(inputIsHeld(BUTTON_DOWN) || inputIsHeld(BUTTON_UP) || (inputIsHeld(leftScrollButton) && canPageUp) || (inputIsHeld(rightScrollButton) && canPageDown)) { 105 | if(lastScrollTime == 0 || platformGetTime() - lastScrollTime >= 180) { 106 | if(inputIsHeld(BUTTON_DOWN) && cursor < (int) elements.size() - 1) { 107 | cursor++; 108 | if(cursor >= scroll + 20) { 109 | scroll++; 110 | } 111 | } 112 | 113 | if(canPageDown && inputIsHeld(rightScrollButton) && cursor < (int) elements.size() - 1) { 114 | cursor += 20; 115 | if(cursor >= (int) elements.size()) { 116 | cursor = elements.size() - 1; 117 | if(cursor < 0) { 118 | cursor = 0; 119 | } 120 | } 121 | 122 | scroll += 20; 123 | if(scroll >= (int) elements.size() - 19) { 124 | scroll = elements.size() - 20; 125 | if(scroll < 0) { 126 | scroll = 0; 127 | } 128 | } 129 | } 130 | 131 | if(inputIsHeld(BUTTON_UP) && cursor > 0) { 132 | cursor--; 133 | if(cursor < scroll) { 134 | scroll--; 135 | } 136 | } 137 | 138 | if(canPageUp && inputIsHeld(leftScrollButton) && cursor > 0) { 139 | cursor -= 20; 140 | if(cursor < 0) { 141 | cursor = 0; 142 | } 143 | 144 | scroll -= 20; 145 | if(scroll < 0) { 146 | scroll = 0; 147 | } 148 | } 149 | 150 | selectionScroll = 0; 151 | selectionScrollEndTime = 0; 152 | 153 | lastScrollTime = platformGetTime(); 154 | } 155 | } else { 156 | lastScrollTime = 0; 157 | } 158 | 159 | gpuViewport(BOTTOM_SCREEN, 0, 0, BOTTOM_WIDTH, BOTTOM_HEIGHT); 160 | gputOrtho(0, BOTTOM_WIDTH, 0, BOTTOM_HEIGHT, -1, 1); 161 | gpuClear(); 162 | 163 | u32 screenWidth = (u32) gpuGetViewportWidth(); 164 | int screenHeight = gpuGetViewportHeight(); 165 | for(std::vector::iterator it = elements.begin() + scroll; it != elements.begin() + scroll + 20 && it != elements.end(); it++) { 166 | SelectableElement element = *it; 167 | int index = it - elements.begin(); 168 | u8 color = 255; 169 | int offset = 0; 170 | float itemHeight = gputGetStringHeight(element.name, 8) + 4; 171 | if(index == cursor) { 172 | color = 0; 173 | 174 | gputPushModelView(); 175 | gputTranslate(0, (screenHeight - 1) - ((index - scroll + 1) * itemHeight), 0); 176 | gpuBindTexture(TEXUNIT0, selectorTexture); 177 | gpuDrawVbo(selectorVbo); 178 | gputPopModelView(); 179 | 180 | u32 width = (u32) gputGetStringWidth(element.name, 8); 181 | if(width > screenWidth) { 182 | if(selectionScroll + screenWidth >= width) { 183 | if(selectionScrollEndTime == 0) { 184 | selectionScrollEndTime = platformGetTime(); 185 | } else if(platformGetTime() - selectionScrollEndTime >= 4000) { 186 | selectionScroll = 0; 187 | selectionScrollEndTime = 0; 188 | } 189 | } else { 190 | selectionScroll++; 191 | } 192 | } 193 | 194 | offset = -selectionScroll; 195 | } 196 | 197 | gputDrawString(element.name, offset, (screenHeight - 1) - ((index - scroll + 1) * itemHeight) + 2, 8, 8, color, color, color); 198 | } 199 | 200 | gpuFlush(); 201 | gpuFlushBuffer(); 202 | 203 | gpuViewport(TOP_SCREEN, 0, 0, TOP_WIDTH, TOP_HEIGHT); 204 | gputOrtho(0, TOP_WIDTH, 0, TOP_HEIGHT, -1, 1); 205 | if(useTopScreen) { 206 | gpuClear(); 207 | 208 | SelectableElement currSelected = elements.at((u32) cursor); 209 | if(currSelected.details.size() != 0) { 210 | std::stringstream details; 211 | for(std::vector::iterator it = currSelected.details.begin(); it != currSelected.details.end(); it++) { 212 | details << *it << "\n"; 213 | } 214 | 215 | gputDrawString(details.str(), 0, gpuGetViewportHeight() - 1 - gputGetStringHeight(details.str(), 8), 8, 8); 216 | } 217 | } 218 | 219 | bool result = onLoop != NULL && onLoop(elements, elements.at((u32) cursor), elementsDirty, resetCursorIfDirty); 220 | if(elementsDirty) { 221 | if(resetCursorIfDirty) { 222 | cursor = 0; 223 | scroll = 0; 224 | } else if(cursor >= (int) elements.size()) { 225 | cursor = elements.size() - 1; 226 | if(cursor < 0) { 227 | cursor = 0; 228 | } 229 | 230 | scroll = elements.size() - 20; 231 | if(scroll < 0) { 232 | scroll = 0; 233 | } 234 | } 235 | 236 | selectionScroll = 0; 237 | selectionScrollEndTime = 0; 238 | if(alphabetize) { 239 | std::sort(elements.begin(), elements.end(), uiAlphabetize()); 240 | } 241 | 242 | elementsDirty = false; 243 | resetCursorIfDirty = true; 244 | } 245 | 246 | if(useTopScreen) { 247 | gpuFlush(); 248 | gpuFlushBuffer(); 249 | } 250 | 251 | gpuSwapBuffers(true); 252 | if(result) { 253 | break; 254 | } 255 | } 256 | 257 | return false; 258 | } 259 | 260 | void uiGetDirContents(std::vector &elements, const std::string directory, std::vector extensions) { 261 | elements.clear(); 262 | elements.push_back({".", "."}); 263 | elements.push_back({"..", ".."}); 264 | 265 | std::vector contents = fsGetDirectoryContents(directory); 266 | for(std::vector::iterator it = contents.begin(); it != contents.end(); it++) { 267 | const std::string name = (*it).name; 268 | const std::string path = (*it).path; 269 | if(fsIsDirectory(path)) { 270 | elements.push_back({path, name}); 271 | } else if(fsHasExtensions(path, extensions)) { 272 | struct stat st; 273 | stat(path.c_str(), &st); 274 | 275 | std::vector info; 276 | std::stringstream stream; 277 | stream << "File Size: " << ((u32) st.st_size) << " bytes (" << std::fixed << std::setprecision(2) << ((u32) st.st_size) / 1024.0f / 1024.0f << "MB)"; 278 | info.push_back(stream.str()); 279 | 280 | std::string extension = fsGetExtension(path); 281 | if(extension.compare("cia") == 0) { 282 | App app = appGetCiaInfo(path, SD); 283 | 284 | std::stringstream titleId; 285 | titleId << "0x" << std::setfill('0') << std::setw(16) << std::hex << app.titleId; 286 | 287 | std::stringstream uniqueId; 288 | uniqueId << "0x" << std::setfill('0') << std::setw(8) << std::hex << app.uniqueId; 289 | 290 | std::stringstream version; 291 | version << "0x" << std::setfill('0') << std::hex << app.version; 292 | 293 | std::stringstream size; 294 | size << "" << app.size << " bytes (" << std::fixed << std::setprecision(2) << app.size / 1024.0f / 1024.0f << "MB)"; 295 | 296 | info.push_back("Installed Size: " + size.str()); 297 | info.push_back("Title ID: " + titleId.str()); 298 | info.push_back("Unique ID: " + uniqueId.str()); 299 | info.push_back("Product Code: " + std::string(app.productCode)); 300 | info.push_back("Platform: " + appGetPlatformName(app.platform)); 301 | info.push_back("Category: " + appGetCategoryName(app.category)); 302 | info.push_back("Version: " + version.str()); 303 | } 304 | 305 | elements.push_back({path, name, info}); 306 | } 307 | } 308 | } 309 | 310 | bool uiSelectFile(std::string* selectedFile, const std::string rootDirectory, std::vector extensions, std::function onLoop, std::function onSelect, bool useTopScreen, bool dpadPageScroll) { 311 | std::stack directoryStack; 312 | std::string currDirectory = rootDirectory; 313 | 314 | std::vector elements; 315 | uiGetDirContents(elements, currDirectory, extensions); 316 | 317 | bool updateContents = false; 318 | bool resetCursor = true; 319 | SelectableElement selected; 320 | bool result = uiSelect(&selected, elements, [&](std::vector &currElements, SelectableElement currElement, bool &elementsDirty, bool &resetCursorIfDirty) { 321 | if(onLoop != NULL && onLoop(currDirectory, directoryStack.empty(), updateContents)) { 322 | return true; 323 | } 324 | 325 | if(inputIsPressed(BUTTON_B) && !directoryStack.empty()) { 326 | currDirectory = directoryStack.top(); 327 | directoryStack.pop(); 328 | updateContents = true; 329 | } 330 | 331 | if(updateContents) { 332 | uiGetDirContents(currElements, currDirectory, extensions); 333 | elementsDirty = true; 334 | resetCursorIfDirty = resetCursor; 335 | updateContents = false; 336 | resetCursor = true; 337 | } 338 | 339 | return false; 340 | }, [&](SelectableElement select) { 341 | if(select.name.compare(".") == 0) { 342 | return false; 343 | } else if(select.name.compare("..") == 0) { 344 | if(!directoryStack.empty()) { 345 | currDirectory = directoryStack.top(); 346 | directoryStack.pop(); 347 | updateContents = true; 348 | } 349 | 350 | return false; 351 | } else if(fsIsDirectory(select.id)) { 352 | directoryStack.push(currDirectory); 353 | currDirectory = select.id; 354 | updateContents = true; 355 | return false; 356 | } 357 | 358 | bool updateList = false; 359 | bool ret = onSelect(select.id, updateList); 360 | if(updateList) { 361 | updateContents = true; 362 | resetCursor = false; 363 | } 364 | 365 | return ret; 366 | }, useTopScreen, true, dpadPageScroll); 367 | 368 | if(result) { 369 | *selectedFile = selected.id; 370 | } 371 | 372 | return result; 373 | } 374 | 375 | void uiGetApps(std::vector &elements, std::vector apps) { 376 | elements.clear(); 377 | for(std::vector::iterator it = apps.begin(); it != apps.end(); it++) { 378 | App app = *it; 379 | 380 | std::stringstream titleId; 381 | titleId << "0x" << std::setfill('0') << std::setw(16) << std::hex << app.titleId; 382 | 383 | std::stringstream uniqueId; 384 | uniqueId << "0x" << std::setfill('0') << std::setw(8) << std::hex << app.uniqueId; 385 | 386 | std::stringstream version; 387 | version << "0x" << std::setfill('0') << std::hex << app.version; 388 | 389 | std::stringstream size; 390 | size << "" << app.size << " bytes (" << std::fixed << std::setprecision(2) << app.size / 1024.0f / 1024.0f << "MB)"; 391 | 392 | std::vector details; 393 | details.push_back("Title ID: " + titleId.str()); 394 | details.push_back("Unique ID: " + uniqueId.str()); 395 | details.push_back("Product Code: " + std::string(app.productCode)); 396 | details.push_back("Platform: " + appGetPlatformName(app.platform)); 397 | details.push_back("Category: " + appGetCategoryName(app.category)); 398 | details.push_back("Version: " + version.str()); 399 | details.push_back("Size: " + size.str()); 400 | 401 | elements.push_back({titleId.str(), app.productCode, details}); 402 | } 403 | 404 | if(elements.size() == 0) { 405 | elements.push_back({"None", "None"}); 406 | } 407 | } 408 | 409 | bool uiFindApp(App* result, std::string id, std::vector apps) { 410 | for(std::vector::iterator it = apps.begin(); it != apps.end(); it++) { 411 | App app = *it; 412 | if(app.titleId == (u64) strtoll(id.c_str(), NULL, 16)) { 413 | *result = app; 414 | return true; 415 | } 416 | } 417 | 418 | return false; 419 | } 420 | 421 | bool uiSelectApp(App* selectedApp, MediaType mediaType, std::function onLoop, std::function onSelect, bool useTopScreen, bool dpadPageScroll) { 422 | std::vector elements; 423 | 424 | std::vector apps = appList(mediaType); 425 | uiGetApps(elements, apps); 426 | 427 | bool updateContents = false; 428 | SelectableElement selected; 429 | bool result = uiSelect(&selected, elements, [&](std::vector &currElements, SelectableElement currElement, bool &elementsDirty, bool &resetCursorIfDirty) { 430 | if(onLoop != NULL && onLoop(updateContents)) { 431 | return true; 432 | } 433 | 434 | if(updateContents) { 435 | apps = appList(mediaType); 436 | uiGetApps(currElements, apps); 437 | elementsDirty = true; 438 | resetCursorIfDirty = false; 439 | updateContents = false; 440 | } 441 | 442 | return false; 443 | }, [&](SelectableElement select) { 444 | if(select.name.compare("None") != 0) { 445 | App app; 446 | if(uiFindApp(&app, select.id, apps)) { 447 | bool updateList = false; 448 | bool ret = onSelect(app, updateList); 449 | if(updateList) { 450 | updateContents = true; 451 | } 452 | 453 | return ret; 454 | } 455 | } 456 | 457 | return false; 458 | }, useTopScreen, true, dpadPageScroll); 459 | 460 | if(result) { 461 | App app; 462 | if(uiFindApp(&app, selected.id, apps)) { 463 | *selectedApp = app; 464 | } 465 | } 466 | 467 | return result; 468 | } 469 | 470 | void uiDisplayMessage(Screen screen, const std::string message) { 471 | gpuViewport(screen, 0, 0, screen == TOP_SCREEN ? TOP_WIDTH : BOTTOM_WIDTH, screen == TOP_SCREEN ? TOP_HEIGHT : BOTTOM_HEIGHT); 472 | gputOrtho(0, screen == TOP_SCREEN ? TOP_WIDTH : BOTTOM_WIDTH, 0, screen == TOP_SCREEN ? TOP_HEIGHT : BOTTOM_HEIGHT, -1, 1); 473 | 474 | gpuClear(); 475 | gputDrawString(message, (gpuGetViewportWidth() - gputGetStringWidth(message, 8)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(message, 8)) / 2, 8, 8); 476 | gpuFlush(); 477 | gpuFlushBuffer(); 478 | gpuSwapBuffers(true); 479 | 480 | gpuViewport(TOP_SCREEN, 0, 0, TOP_WIDTH, TOP_HEIGHT); 481 | gputOrtho(0, TOP_WIDTH, 0, TOP_HEIGHT, -1, 1); 482 | } 483 | 484 | bool uiPrompt(Screen screen, const std::string message, bool question) { 485 | std::stringstream stream; 486 | stream << message << "\n"; 487 | if(question) { 488 | stream << "Press A to confirm, B to cancel." << "\n"; 489 | } else { 490 | stream << "Press Start to continue." << "\n"; 491 | } 492 | 493 | bool result = false; 494 | std::string str = stream.str(); 495 | while(platformIsRunning()) { 496 | inputPoll(); 497 | if(question) { 498 | if(inputIsPressed(BUTTON_A)) { 499 | result = true; 500 | break; 501 | } 502 | 503 | if(inputIsPressed(BUTTON_B)) { 504 | result = false; 505 | break; 506 | } 507 | } else { 508 | if(inputIsPressed(BUTTON_START)) { 509 | result = true; 510 | break; 511 | } 512 | } 513 | 514 | uiDisplayMessage(screen, str); 515 | } 516 | 517 | inputPoll(); 518 | return result; 519 | } 520 | 521 | void uiDisplayProgress(Screen screen, const std::string operation, const std::string details, bool quickSwap, u32 progress) { 522 | std::stringstream stream; 523 | stream << operation << ": ["; 524 | u32 progressBars = progress / 4; 525 | for(u32 i = 0; i < 25; i++) { 526 | if(i < progressBars) { 527 | stream << '|'; 528 | } else { 529 | stream << ' '; 530 | } 531 | } 532 | 533 | stream << "] " << std::setfill(' ') << std::setw(3) << progress << "%" << "\n"; 534 | stream << details << "\n"; 535 | 536 | std::string str = stream.str(); 537 | 538 | gpuViewport(screen, 0, 0, screen == TOP_SCREEN ? TOP_WIDTH : BOTTOM_WIDTH, screen == TOP_SCREEN ? TOP_HEIGHT : BOTTOM_HEIGHT); 539 | gputOrtho(0, screen == TOP_SCREEN ? TOP_WIDTH : BOTTOM_WIDTH, 0, screen == TOP_SCREEN ? TOP_HEIGHT : BOTTOM_HEIGHT, -1, 1); 540 | 541 | gpuClear(); 542 | gputDrawString(str, (gpuGetViewportWidth() - gputGetStringWidth(str, 8)) / 2, (gpuGetViewportHeight() - gputGetStringHeight(str, 8)) / 2, 8, 8); 543 | gpuFlush(); 544 | gpuFlushBuffer(); 545 | gpuSwapBuffers(!quickSwap); 546 | 547 | gpuViewport(TOP_SCREEN, 0, 0, TOP_WIDTH, TOP_HEIGHT); 548 | gputOrtho(0, TOP_WIDTH, 0, TOP_HEIGHT, -1, 1); 549 | } 550 | 551 | RemoteFile uiAcceptRemoteFile(Screen screen, std::function onWait) { 552 | uiDisplayMessage(screen, "Initializing..."); 553 | 554 | int listen = socketListen(5000); 555 | if(listen < 0) { 556 | std::stringstream errStream; 557 | errStream << "Failed to initialize." << "\n" << strerror(errno) << "\n"; 558 | uiPrompt(screen, errStream.str(), false); 559 | return {NULL, 0}; 560 | } 561 | 562 | std::stringstream baseInfoStream; 563 | baseInfoStream << "Waiting for peer to connect..." << "\n"; 564 | baseInfoStream << "IP: " << inet_ntoa({socketGetHostIP()}) << "\n"; 565 | baseInfoStream << "Press B to cancel." << "\n"; 566 | std::string baseInfo = baseInfoStream.str(); 567 | 568 | FILE* socket; 569 | while((socket = socketAccept(listen)) == NULL) { 570 | if(!platformIsRunning()) { 571 | close(listen); 572 | return {NULL, 0}; 573 | } 574 | 575 | if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) { 576 | close(listen); 577 | 578 | std::stringstream errStream; 579 | errStream << "Failed to accept peer." << "\n" << strerror(errno) << "\n"; 580 | uiPrompt(screen, errStream.str(), false); 581 | 582 | return {NULL, 0}; 583 | } 584 | 585 | inputPoll(); 586 | if(inputIsPressed(BUTTON_B)) { 587 | close(listen); 588 | return {NULL, 0}; 589 | } 590 | 591 | std::stringstream infoStream; 592 | infoStream << baseInfo; 593 | onWait(infoStream); 594 | uiDisplayMessage(screen, infoStream.str()); 595 | } 596 | 597 | close(listen); 598 | 599 | uiDisplayMessage(screen, "Reading info...\nPress B to cancel."); 600 | 601 | u64 fileSize = 0; 602 | u64 bytesRead = 0; 603 | while(bytesRead < sizeof(fileSize)) { 604 | if(!platformIsRunning()) { 605 | fclose(socket); 606 | return {NULL, 0}; 607 | } 608 | 609 | size_t currBytesRead = fread(&fileSize + bytesRead, 1, (size_t) (sizeof(fileSize) - bytesRead), socket); 610 | if(currBytesRead > 0) { 611 | bytesRead += currBytesRead; 612 | } 613 | 614 | if(ferror(socket) && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) { 615 | fclose(socket); 616 | 617 | std::stringstream errStream; 618 | errStream << "Failed to read info." << "\n" << strerror(errno) << "\n"; 619 | uiPrompt(screen, errStream.str(), false); 620 | 621 | return {NULL, 0}; 622 | } 623 | 624 | inputPoll(); 625 | if(inputIsPressed(BUTTON_B)) { 626 | fclose(socket); 627 | return {NULL, 0}; 628 | } 629 | } 630 | 631 | fileSize = ntohll(fileSize); 632 | return {socket, fileSize}; 633 | } --------------------------------------------------------------------------------