├── .gitignore ├── COPYING.txt ├── CREDITS ├── Doxyfile ├── LICENSE-GPL2.txt ├── LICENSE-GPL3.txt ├── Makefile.am ├── README ├── common.mk ├── configure.ac ├── cppcheck.cppcheck ├── doc ├── README └── input_output_layer.txt ├── examples ├── Makefile.am ├── example1.c ├── example2.c └── example3.c ├── include └── ctr9 │ ├── aes.h │ ├── ctr_aeskeydb.h │ ├── ctr_cache.h │ ├── ctr_circular_buffer.h │ ├── ctr_elf_loader.h │ ├── ctr_firm.h │ ├── ctr_freetype.h │ ├── ctr_headers.h │ ├── ctr_hid.h │ ├── ctr_interrupt.h │ ├── ctr_irq.h │ ├── ctr_memory.h │ ├── ctr_pxi.h │ ├── ctr_rtc.h │ ├── ctr_screen.h │ ├── ctr_system.h │ ├── ctr_system_clock.h │ ├── ctr_timer.h │ ├── gamecart │ ├── command_ctr.h │ ├── command_ntr.h │ ├── protocol.h │ ├── protocol_ctr.h │ └── protocol_ntr.h │ ├── i2c.h │ ├── io.h │ ├── io │ ├── ctr_cart_interface.h │ ├── ctr_console.h │ ├── ctr_crypto_interface.h │ ├── ctr_disks.h │ ├── ctr_drives.h │ ├── ctr_file_interface.h │ ├── ctr_io_implementation.c │ ├── ctr_io_implementation.h │ ├── ctr_io_interface.h │ ├── ctr_memory_interface.h │ ├── ctr_nand_crypto_interface.h │ ├── ctr_nand_interface.h │ ├── ctr_sd_interface.h │ ├── ctr_sdmmc_implementation.c │ ├── ctr_sdmmc_implementation.h │ ├── fatfs │ │ ├── ctr_fatfs.h │ │ ├── ctr_fatfs_disk.h │ │ ├── diskio.h │ │ ├── ff.h │ │ ├── ffconf.h │ │ └── integer.h │ └── sdmmc │ │ └── sdmmc.h │ └── sha.h ├── libctr9.pc.in ├── src ├── Makefile.am ├── aes.c ├── crt0.s ├── ctr_aeskeydb.c ├── ctr_cache.s ├── ctr_cart_interface.c ├── ctr_circular_buffer.c ├── ctr_console.c ├── ctr_crypto_interface.c ├── ctr_disks.c ├── ctr_drives.c ├── ctr_elf_loader.c ├── ctr_fatfs.c ├── ctr_file_interface.c ├── ctr_firm.c ├── ctr_freetype.c ├── ctr_headers.c ├── ctr_hid.c ├── ctr_init.c ├── ctr_interrupt.c ├── ctr_interrupt_asm.s ├── ctr_io_interface.c ├── ctr_irq.c ├── ctr_memory.c ├── ctr_memory_asm.s ├── ctr_memory_interface.c ├── ctr_nand_crypto_interface.c ├── ctr_nand_interface.c ├── ctr_pxi.c ├── ctr_rtc.c ├── ctr_screen.c ├── ctr_sd_interface.c ├── ctr_system.c ├── ctr_system_clock.c ├── ctr_timer.c ├── fatfs │ ├── 00history.txt │ ├── 00readme.txt │ ├── ctr_fatfs_disk.c │ ├── diskio.c │ ├── ff.c │ └── option │ │ ├── cc932.c │ │ ├── cc936.c │ │ ├── cc949.c │ │ ├── cc950.c │ │ ├── ccsbcs.c │ │ ├── syscall.c │ │ └── unicode.c ├── gamecart │ ├── command_ctr.c │ ├── command_ntr.c │ ├── delay.h │ ├── delay.s │ ├── protocol.c │ ├── protocol_ctr.c │ └── protocol_ntr.c ├── i2c.c ├── linker.ld ├── sdmmc │ ├── delay.s │ └── sdmmc.c └── sha.c └── test ├── .gitignore ├── Makefile.am ├── arm9loaderhax.ld ├── crypto_memory_tests.c ├── crypto_memory_tests.h ├── interrupt.c ├── interrupt.h ├── main.c ├── memory_control_tests.c ├── memory_control_tests.h ├── memory_tests.c ├── memory_tests.h ├── nand_crypto_tests.c ├── nand_crypto_tests.h ├── nand_tests.c ├── nand_tests.h ├── sd_tests.c ├── sd_tests.h ├── test.c ├── test.h ├── twl_tests.c └── twl_tests.h /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | lib 3 | *.swp 4 | *.in 5 | *.o 6 | *.lo 7 | .deps 8 | doc 9 | *.a 10 | *.la 11 | *.pc 12 | Makefile 13 | aclocal.m4 14 | autom4te.cache 15 | compile 16 | config.guess 17 | config.log 18 | config.status 19 | config.sub 20 | configure 21 | .dirstamp 22 | depcomp 23 | install-sh 24 | libtool 25 | ltmain.sh 26 | missing 27 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | (Work in progress) libctr9_io, a 3DS ARM9 disk IO framework and library. 2 | Copyright (C) 2016 Gabriel Marcano 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | Only code written by Gabriel Marcano is under the terms of the GPL as 18 | outlined above. Other projects in use and their licenses: 19 | 20 | sdmmc by Normmatt: Licensed under the MPL 2.0 (refer to sdmmc.h an 21 | sdmmc.c) 22 | aes and sha were taken from Godmode9 by d0k3: Licensed under the GPL 3.0 or 23 | 2.0 ??? seems to have been originally written by megazig 24 | fatfs by ChaN: BSD-style licenced. Refer to 25 | http://elm-chan.org/fsw/ff/en/appnote.html#license for more 26 | information. 27 | gamecart by Normmatt: Licensed under the GPL 2.0 or later. 28 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Normmatt, d0k3, ChaN, megazig?, Nintendo, bilis (FIXME who else am I forgetting?) 2 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src test examples 2 | 3 | pkgconfigdir = $(libdir)/pkgconfig 4 | pkgconfig_DATA = libctr9.pc 5 | 6 | EXTRA_DIST = Doxyfile 7 | -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | INCPATHS=-I$(top_srcdir)/include -I$(prefix)/include/freetype2 2 | 3 | C9FLAGS=-mcpu=arm946e-s -march=armv5te -mlittle-endian -mword-relocations 4 | 5 | THUMBFLAGS=-mthumb #-mthumb-interwork 6 | SIZE_OPTIMIZATION = -flto 7 | #SIZE_OPTIMIZATION = -Wl,--gc-sections -ffunction-sections 8 | AM_CPPFLAGS=$(INCPATHS) 9 | ARM_ONLY= -std=gnu11 -O2 -g -fomit-frame-pointer -ffast-math \ 10 | -Wpedantic -Wall -Wextra -Wcast-align -Wcast-qual \ 11 | -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op \ 12 | -Wmissing-declarations -Wmissing-include-dirs -Wredundant-decls \ 13 | -Wshadow -Wsign-conversion -Wstrict-overflow=5 -Wswitch-default \ 14 | -Wundef -Wno-unused $(C9FLAGS) $(SIZE_OPTIMIZATION) 15 | AM_CFLAGS=$(ARM_ONLY) $(THUMBFLAGS) 16 | AM_LDFLAGS=-Wl,--use-blx,--pic-veneer,-q 17 | OCFLAGS=--set-section-flags .bss=alloc,load,contents 18 | 19 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libctr9], [0.0.2], [], []) 2 | AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-xz subdir-objects]) 3 | 4 | #Find AR and RANLIB for lto support before initializing libtool 5 | AC_CHECK_TOOL([AR],gcc-ar) 6 | AC_CHECK_TOOL([RANLIB],gcc-ranlib) 7 | LT_INIT 8 | 9 | AC_PROG_CC 10 | AM_PROG_AS 11 | AC_CHECK_TOOL([OBJCOPY],objcopy) 12 | 13 | AC_CHECK_HEADERS([ft2build.h freetype2/ft2build.h], [break], [FT_FOUND=1]) 14 | 15 | if test "$FT_FOUND" == "1" 16 | then 17 | AC_MSG_ERROR( 18 | [unable to find ft2build.h, make sure FreeType2 is installed and\ 19 | that the right -I flag is set.]) 20 | fi 21 | 22 | AC_CONFIG_FILES([Makefile src/Makefile test/Makefile examples/Makefile libctr9.pc]) 23 | AC_OUTPUT 24 | 25 | -------------------------------------------------------------------------------- /cppcheck.cppcheck: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | Documentation 3 | -------------------------------------------------------------------------------- 4 | 5 | This project uses Doxygen markup in order to facilitate the generation of 6 | documentation, which should be found when generated in the doc/ folder. Each 7 | header in the include/ directory should also be well documented and can be used 8 | as reference for programming. 9 | 10 | In addition, some documentation is hosted in GitHub pages: 11 | https://gemarcano.github.io/libctr9/ 12 | 13 | In this folder there are explanations about the general design decisions taken. 14 | 15 | -------------------------------------------------------------------------------- /doc/input_output_layer.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | Design: IO subsystem/framework 3 | -------------------------------------------------------------------------------- 4 | 5 | The IO framework is based on the idea of IO interfaces that can be layered. The 6 | implementation of each IO interface layer depends on a function table that is 7 | embedded into the IO interface context object. It is via this function table 8 | that the generic IO interface functions determine what function to call, acting 9 | as a virtual table for the IO interface functionality. Refer to 10 | ctr_io_interface.h for the definition of this function table. 11 | 12 | One of the advantages of the framework is that it lends itself well to layering 13 | IO interfaces. For example, after implementing a NAND IO interface, it is 14 | possible to develop an IO interface layer that takes as an input at 15 | initialization a NAND IO interface and transforms the input/output of the NAND 16 | IO interface layer as necessary. An example of this is the crypto IO interface 17 | layer included in this library, which takes as an input any IO interface layer 18 | (most likely NAND) and then applies crypto to the input/output to/from the 19 | NAND IO layer, based on the initialization parameters of the crypto layer. This 20 | allows for the encrypted NAND to be read and written transparently, for example. 21 | 22 | The IO subsystem was designed with extensibility in mind. In order to create a 23 | new IO interface layer, all one needs to do is implement six functions and 24 | load a function table at the beginning of the new IO interface object with those 25 | functions. Instead of calling the function pointers directly, use the ctr_io_* 26 | functions supplied by the framework. These will make sure to call the right 27 | functions. 28 | 29 | For examples of how IO interfaces are implemented refer to the source code for 30 | this library. Some example IO interfaces are ctr_nand_interface (the actual 31 | implementation for this one was abstracted to ctr_sdmmc_implementation), 32 | ctr_nand_crypto_interface, and ctr_fatfs_interface. It is feasible to make a 33 | ctr_xorpad_interface to generate xorpads, for example, taking two IO interface 34 | layers, one providing the raw encrypted ouput and another the plaintext. 35 | 36 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | include $(top_srcdir)/common.mk 2 | 3 | EXTRA_PROGRAMS = example1 example2 example3 example4 4 | 5 | example1_CFLAGS=$(AM_CFLAGS) -T$(top_srcdir)/src/linker.ld -L${prefix}/lib -I${prefix}/include/freetype2 6 | example1_LDADD = $(AM_LDADD) $(top_builddir)/src/libctr9.a -lfreetype -lctr -lm 7 | example1_SOURCES = example1.c 8 | example2_CFLAGS=$(AM_CFLAGS) -T$(top_srcdir)/src/linker.ld -L${prefix}/lib -I${prefix}/include/freetype2 9 | example2_LDADD = $(AM_LDADD) $(top_builddir)/src/libctr9.a -lfreetype -lctr -lm 10 | example2_SOURCES = example2.c 11 | example3_CFLAGS=$(AM_CFLAGS) -T$(top_srcdir)/src/linker.ld -L${prefix}/lib -I${prefix}/include/freetype2 12 | example3_LDADD = $(AM_LDADD) $(top_builddir)/src/libctr9.a -lfreetype -lctr -lm 13 | example3_SOURCES = example3.c 14 | 15 | .PHONY: FORCE 16 | 17 | FORCE: 18 | 19 | $(top_builddir)/src/libctr9.a: FORCE 20 | (cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) libctr9.a ) 21 | 22 | clean-local: 23 | -rm -f example1 example2 example3 24 | -------------------------------------------------------------------------------- /examples/example1.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | 11 | /* This example goes over how to initialize the basic IO infrastructure to 12 | * access raw NAND. 13 | */ 14 | 15 | int main() 16 | { 17 | //All of the IO subsystem is built around the idea of IO objects that hold 18 | //the state of the IO subsystems, and IO functions that act on these 19 | //objects. 20 | //In this case, since this is used for raw NAND access, only the nand io 21 | //interface is needed. Make sure to initialize the object before calling any 22 | //ctr_io_* functions with it. 23 | ctr_nand_interface nand_io; 24 | ctr_nand_interface_initialize(&nand_io); 25 | 26 | //Allocate a small buffer to read to 27 | unsigned char buffer[0x200] = { 0 }; 28 | 29 | //The IO subsystem implements polymorphism, so any io interface can be used 30 | //as an input to the ctr_io_* functions. 31 | 32 | //Read the size of the buffer into the buffer we allocated earlier, starting 33 | //from the beginning of NAND. Effectively, read the NCSD header. 34 | ctr_io_read(&nand_io, buffer, sizeof(buffer), 0x0, sizeof(buffer)); 35 | 36 | //Destroy the io interface object when done with it. 37 | ctr_nand_interface_destroy(&nand_io); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /examples/example2.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | 11 | /* This example goes over how to manually gain en/decrypted access to NAND. It 12 | * also serves as an example of how the layer concept for io interfaces work. 13 | */ 14 | 15 | int main() 16 | { 17 | //Declare the io interface objects that will be used. For accessing the 18 | //encrypted data inside NAND, that means NAND itself must be initialized, as 19 | //well as the layers that will deal with the decryption of the data. In this 20 | //case, both a crypto layer for ctr and twl need to be declared. 21 | ctr_nand_interface nand_io; 22 | ctr_nand_crypto_interface ctr_io; 23 | ctr_nand_crypto_interface twl_io; 24 | 25 | ctr_nand_interface_initialize(&nand_io); 26 | 27 | //To initialize io crypto layer objects, they require knowing which keyslot 28 | //to use for en/decryption as well as which mode of operation. The layer 29 | //used here tries to set up the keys for TWL and CTRNAND on its own. 30 | 31 | //For CTRNAND decryption, use keyslot 0x04, used for the o3DS, set the 32 | //mode for CTR, and pass in the nand object as the object to wrap in the 33 | //crypto layer. 34 | ctr_nand_crypto_interface_initialize(&ctr_io, 0x04, NAND_CTR, (ctr_io_interface*)&nand_io); 35 | 36 | //For TWLN decryption, use keyslot 0x03, used for the o3DS, set the 37 | //mode for TWL, and pass in the nand object as the object to wrap in the 38 | //crypto layer. 39 | 40 | ctr_nand_crypto_interface_initialize(&twl_io, 0x03, NAND_TWL, (ctr_io_interface*)&nand_io); 41 | 42 | //Setup buffers to copy data to 43 | unsigned char ctr_buffer[0x200] = { 0 }; 44 | unsigned char twl_buffer[0x200] = { 0 }; 45 | 46 | //Read the beginning of CTRNAND 47 | ctr_io_read(&ctr_io, ctr_buffer, sizeof(ctr_buffer), 0x0B930000, sizeof(ctr_buffer)); 48 | 49 | //Read the beginning of TWLN 50 | ctr_io_read(&twl_io, twl_buffer, sizeof(twl_buffer), 0x00012E00, sizeof(twl_buffer)); 51 | 52 | ctr_nand_crypto_interface_destroy(&twl_io); 53 | ctr_nand_crypto_interface_destroy(&ctr_io); 54 | ctr_nand_interface_destroy(&nand_io); 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /examples/example3.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | /* This example goes over how to use file and console IO. 15 | */ 16 | 17 | int main() 18 | { 19 | //using ctr_libctr9_init(), which a developer can override since it is a 20 | //weakly linked symbol, by default libctr9 initializes the IO and console 21 | //subsystems. FILE operations and printf should just work unless libctr9 22 | //encountered an error. 23 | 24 | //ctr_drives_check_ready checks to see that the given drive is working 25 | //properly. Returns true if the drive is ready and can be used. 26 | bool sd = ctr_drives_check_ready("SD:"); 27 | bool ctrnand = ctr_drives_check_ready("CTRNAND:"); 28 | bool twln = ctr_drives_check_ready("TWLN:"); 29 | bool twlp = ctr_drives_check_ready("TWLP:"); 30 | 31 | printf("SD: %d, CTRNAND: %d, TWLN: %d, TWLP: %d\n", sd, ctrnand, twln, twlp); 32 | 33 | //To open a file, use fopen, using the drive as the prefix for the path. 34 | FILE *file = fopen("SD:/tmp.txt", "r+b"); 35 | if (file) 36 | { 37 | printf("File did open, now closing...\n"); 38 | fclose(file); 39 | } 40 | 41 | //ctr_drives_chdrive can be used to change the default drive used 42 | ctr_drives_chdrive("CTRNAND:"); 43 | 44 | file = fopen("/rw/sys/SecureInfo_A", "rb"); 45 | if (file) 46 | { 47 | printf("SecureInfo_A was found, now closing...\n"); 48 | fclose(file); 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /include/ctr9/aes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define AES_BLOCK_SIZE 0x10 11 | 12 | #define AES_CCM_DECRYPT_MODE (0u << 27) 13 | #define AES_CCM_ENCRYPT_MODE (1u << 27) 14 | #define AES_CTR_MODE (2u << 27) 15 | #define AES_CBC_DECRYPT_MODE (4u << 27) 16 | #define AES_CBC_ENCRYPT_MODE (5u << 27) 17 | #define AES_ECB_DECRYPT_MODE (6u << 27) 18 | #define AES_ECB_ENCRYPT_MODE (7u << 27) 19 | 20 | #define REG_AESCNT ((volatile uint32_t*)0x10009000) 21 | #define REG_AESBLKCNT ((volatile uint32_t*)0x10009004) 22 | #define REG_AESWRFIFO ((volatile uint32_t*)0x10009008) 23 | #define REG_AESRDFIFO ((volatile uint32_t*)0x1000900C) 24 | #define REG_AESKEYSEL ((volatile uint8_t *)0x10009010) 25 | #define REG_AESKEYCNT ((volatile uint8_t *)0x10009011) 26 | #define REG_AESCTR ((volatile uint32_t*)0x10009020) 27 | #define REG_AESKEYFIFO ((volatile uint32_t*)0x10009100) 28 | #define REG_AESKEYXFIFO ((volatile uint32_t*)0x10009104) 29 | #define REG_AESKEYYFIFO ((volatile uint32_t*)0x10009108) 30 | #define REG_AESMAC ((volatile uint32_t*)0x10009030) 31 | // see https://www.3dbrew.org/wiki/AES_Registers#AES_KEY0.2F1.2F2.2F3 32 | #define REG_AESKEY0123 ((volatile uint32_t*)0x10009040) 33 | 34 | #define AES_CNT_START 0x80000000u 35 | #define AES_CNT_INPUT_ORDER 0x02000000u 36 | #define AES_CNT_OUTPUT_ORDER 0x01000000u 37 | #define AES_CNT_INPUT_ENDIAN 0x00800000u 38 | #define AES_CNT_OUTPUT_ENDIAN 0x00400000u 39 | #define AES_CNT_FLUSH_READ 0x00000800u 40 | #define AES_CNT_FLUSH_WRITE 0x00000400u 41 | 42 | #define AES_CNT_CTRNAND_MODE (AES_CTR_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 43 | #define AES_CNT_TWLNAND_MODE AES_CTR_MODE 44 | #define AES_CNT_TITLEKEY_DECRYPT_MODE (AES_CBC_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 45 | #define AES_CNT_TITLEKEY_ENCRYPT_MODE (AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 46 | #define AES_CNT_CBC_DECRYPT_MODE (AES_CBC_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 47 | #define AES_CNT_CBC_ENCRYPT_MODE (AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 48 | #define AES_CNT_ECB_DECRYPT_MODE (AES_ECB_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 49 | #define AES_CNT_ECB_ENCRYPT_MODE (AES_ECB_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 50 | 51 | void setup_aeskeyX(uint8_t keyslot, const void* keyx); 52 | void setup_aeskeyY(uint8_t keyslot, const void* keyy); 53 | void setup_aeskey(uint8_t keyslot, const void* keyy); 54 | void use_aeskey(uint32_t keyno); 55 | void set_ctr(void* iv); 56 | void add_ctr(void* ctr, uint32_t carry); 57 | void subtract_ctr(void* ctr, uint32_t carry); 58 | void aes_decrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode); 59 | void ctr_decrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode, uint8_t *ctr); 60 | 61 | void ecb_decrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode); 62 | 63 | void cbc_encrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode, uint8_t *ctr); 64 | void cbc_decrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode, uint8_t *ctr); 65 | void ccm_encrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode, uint8_t *ctr); 66 | void ccm_decrypt(void* inbuf, void* outbuf, size_t blocks, uint32_t mode, uint8_t *ctr); 67 | 68 | void aes_fifos(void* inbuf, void* outbuf, size_t blocks); 69 | void set_aeswrfifo(uint32_t value); 70 | uint32_t read_aesrdfifo(void); 71 | uint32_t aes_getwritecount(void); 72 | uint32_t aes_getreadcount(void); 73 | uint32_t aescnt_checkwrite(void); 74 | uint32_t aescnt_checkread(void); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /include/ctr9/ctr_aeskeydb.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_AESKEYDB_H_ 12 | #define CTR_AESKEYDB_H_ 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | typedef struct 21 | { 22 | uint8_t slot; 23 | char type; 24 | char id[10]; 25 | uint8_t reserved[2]; 26 | uint8_t is_devkit_key; 27 | uint8_t is_encrypted; 28 | uint8_t key[16]; 29 | } ctr_aesdb_entry; 30 | 31 | /** @brief Loads the given entry structure with the data found in memory at the 32 | * given address. 33 | * 34 | * @param[out] entry Entry structure to fill. 35 | * @param[in] data Data in memory that contains the raw aesdb data. This must 36 | * be at least 32 bytes in length. 37 | * 38 | * @post The given entry will have its structure loaded based on the data found 39 | * in memory. 40 | */ 41 | void ctr_aesdb_entry_load(ctr_aesdb_entry *entry, const void *data); 42 | 43 | /** @brief Applies the encryption algorithm to the key in the given entry, as 44 | * designed by d0k3 in Decrypt9. 45 | * 46 | * @param[in,out] entry Entry with the key to be processed through the 47 | * algorithm. 48 | * 49 | * @post The key inside the given entry has been processed through the 50 | * encryption algorithm, and the encryption flag on the entry has been 51 | * updated accordingly. 52 | */ 53 | void ctr_aesdb_entry_crypt_key(ctr_aesdb_entry *entry); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif//CTR_AESKEYDB_H_ 60 | 61 | -------------------------------------------------------------------------------- /include/ctr9/ctr_circular_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_CIRCULAR_BUFFER_H_ 2 | #define CTR_CIRCULAR_BUFFER_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | typedef ctr_core_circular_buffer ctr_circular_buffer; 10 | 11 | void ctr_circular_buffer_initialize(ctr_circular_buffer *buffer, size_t size); 12 | bool ctr_circular_buffer_push_back(ctr_circular_buffer *buffer, char data); 13 | bool ctr_circular_buffer_pop_front(ctr_circular_buffer *buffer, char *data); 14 | bool ctr_circular_buffer_get(ctr_circular_buffer *buffer, size_t index, char *data); 15 | size_t ctr_circular_buffer_size(ctr_circular_buffer *buffer); 16 | size_t ctr_circular_buffer_count(ctr_circular_buffer *buffer); 17 | 18 | #endif//CTR_CIRCULAR_BUFFER_H_ 19 | 20 | -------------------------------------------------------------------------------- /include/ctr9/ctr_elf_loader.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_ELF_LOADER_H_ 12 | #define CTR_ELF_LOADER_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | void ctr_load_header(Elf32_Ehdr *header, FILE *file); 23 | 24 | int ctr_load_segment(const Elf32_Phdr *header, FILE *file); 25 | 26 | int ctr_load_segments(const Elf32_Ehdr *header, FILE *file); 27 | 28 | bool ctr_check_elf(Elf32_Ehdr *header); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif//CTR_ELF_LOADER_H_ 35 | 36 | -------------------------------------------------------------------------------- /include/ctr9/ctr_firm.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_FIRM_H_ 12 | #define CTR_FIRM_H_ 13 | 14 | #include 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** @brief Represents the information found in the firm header describing 23 | * section information. 24 | */ 25 | typedef ctr_core_firm_section_header ctr_firm_section_header; 26 | 27 | /** @brief Represents the information found in the firm header. 28 | */ 29 | typedef ctr_core_firm_header ctr_firm_header; 30 | 31 | /** @brief Represents the information found in the arm9bin header. 32 | */ 33 | typedef ctr_core_arm9bin_header ctr_arm9bin_header; 34 | 35 | /** @brief Loads the given firm section header structure with the values found 36 | * in memory. 37 | * 38 | * @param[out] header Header structure to fill. 39 | * @param[in] data Raw firm section header data found in memory. Must be at 40 | * least 0x30 in size. 41 | * 42 | * @post The given firm section header struct has been filled out based on the 43 | * data found in memory. 44 | */ 45 | void ctr_firm_section_header_load(ctr_firm_section_header *header, const void *data); 46 | 47 | /** @brief Loads the given firm header structure with the values found in 48 | * memory. 49 | * 50 | * @param[out] header Header structure to fill. 51 | * @param[in] data Raw firm header data found in memory. Must be at least 0x200 52 | * in size. 53 | * 54 | * @post The given firm header struct has been filled out based on the data 55 | * found in memory. 56 | */ 57 | void ctr_firm_header_load(ctr_firm_header *header, const void *data); 58 | 59 | /** @brief Loads the given arm9bin header structure with the values found in 60 | * memory. 61 | * 62 | * @param[out] header Header structure to fill. 63 | * @param[in] data Raw arm9bin header data found in memory. Must be at least 0x200 64 | * in size. 65 | * 66 | * @post The given firm header struct has been filled out based on the data 67 | * found in memory. 68 | */ 69 | void ctr_arm9bin_header_load(ctr_arm9bin_header *header, const void *data); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif//TR_FIRM_H_ 76 | 77 | -------------------------------------------------------------------------------- /include/ctr9/ctr_freetype.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_FREETYPE_H_ 12 | #define CTR_FREETYPE_H_ 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include FT_FREETYPE_H 21 | #include FT_CACHE_H 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /** @brief Initializes the freetype subsystem. 28 | */ 29 | int ctr_freetype_initialize(void); 30 | 31 | FT_Face ctr_freetype_get_face(void); 32 | FTC_SBit ctr_freetype_prepare_character(char c); 33 | void ctr_freetype_draw(ctr_screen *screen, size_t x, size_t y, char c, uint32_t pixel, uint32_t bg); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif//CTR_FREETYPE_H_ 40 | 41 | -------------------------------------------------------------------------------- /include/ctr9/ctr_headers.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_HEADERS_H_ 12 | #define CTR_HEADERS_H_ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** @brief Struct representing the NCSD header for carts. 24 | */ 25 | typedef ctr_core_ncsd_cart_header ctr_ncsd_cart_header; 26 | 27 | /** @brief Struct representing the NCCH header. 28 | */ 29 | typedef ctr_core_ncch_header ctr_ncch_header; 30 | 31 | /** @brief Loads the given ctr_ncsd_cart_header with the data from the actual 32 | * NCSD cart header in memory. 33 | * 34 | * @param[out] header Struct to load. 35 | * @param[in] data Pointer to NCSD in memory to load into header struct. 36 | * @param[in] data_size Length of the buffer in memory with the NCSD data. This 37 | * function expects this number to be greater than or equal to 0x200, else 38 | * the function refuses to load the struct, even partially. 39 | * 40 | * @post If data_size >= 0x200, header is updated to include the parsed data 41 | * from the NCSD header in memory, else nothing happens. 42 | */ 43 | void ctr_ncsd_header_load(ctr_ncsd_cart_header *header, const uint8_t *data, size_t data_size); 44 | 45 | /** @brief Loads the given ctr_ncch_header with the data from the actual NCCH 46 | * header in memory. 47 | * 48 | * @param[out] header Struct to load. 49 | * @param[in] data Pointer to NCCH in memory to load into header struct. 50 | * @param[in] data_size Length of the buffer in memory with the NCCH data. This 51 | * function expects this number to be greater than or equal to 0x200, else 52 | * the function refuses to load the struct, even partially. 53 | * 54 | * @post If data_size >= 0x200, header is updated to include the parsed data 55 | * from the NCSD header in memory, else nothing happens. 56 | */ 57 | void ctr_ncch_header_load(ctr_ncch_header *header, const uint8_t *data, size_t data_size); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif//CTR_HEADERS_H_ 64 | 65 | -------------------------------------------------------------------------------- /include/ctr9/ctr_hid.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_HID_H_ 12 | #define CTR_HID_H_ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | //Button type 24 | typedef ctr_core_hid_button_type ctr_hid_button_type; 25 | 26 | //HID Register 27 | #define CTR_HID_REG CTR_CORE_HID_REG 28 | 29 | //Button definitions 30 | #define CTR_HID_NONE CTR_CORE_HID_NONE 31 | #define CTR_HID_A CTR_CORE_HID_A 32 | #define CTR_HID_B CTR_CORE_HID_B 33 | #define CTR_HID_SELECT CTR_CORE_HID_SELECT 34 | #define CTR_HID_START CTR_CORE_HID_START 35 | #define CTR_HID_RIGHT CTR_CORE_HID_RIGHT 36 | #define CTR_HID_LEFT CTR_CORE_HID_LEFT 37 | #define CTR_HID_UP CTR_CORE_HID_UP 38 | #define CTR_HID_DOWN CTR_CORE_HID_DOWN 39 | #define CTR_HID_RT CTR_CORE_HID_RT 40 | #define CTR_HID_LT CTR_CORE_HID_LT 41 | #define CTR_HID_X CTR_CORE_HID_X 42 | #define CTR_HID_Y CTR_CORE_HID_Y 43 | 44 | /** @brief Returns whether the given button combination is pressed or not. 45 | * 46 | * @param[in] buttons Button combination to check if they are pressed. 47 | * 48 | * @returns True if the buttons passed in are pressed, false otherwise. 49 | */ 50 | bool ctr_hid_button_status(ctr_hid_button_type buttons); 51 | 52 | /** @brief Returns all of the buttons pressed at the instant this is called. 53 | * 54 | * @brief returns All of the buttons pressed at the time this function is 55 | * called. 56 | */ 57 | ctr_hid_button_type ctr_hid_get_buttons(void); 58 | 59 | void ctr_input_wait(void); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif//CTR_HID_H_ 66 | 67 | -------------------------------------------------------------------------------- /include/ctr9/ctr_interrupt.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_INTERRUPT_H_ 12 | #define CTR_INTERRUPT_H_ 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /** @brief Enumerations for the different ARM9 CPU exceptions 21 | * 22 | * These enumerations can be used as indices to set handlers for the exceptions 23 | * with ctr_interrupt_set. 24 | */ 25 | typedef enum 26 | { 27 | CTR_INTERRUPT_RESET, 28 | CTR_INTERRUPT_UNDEF, 29 | CTR_INTERRUPT_SWI, 30 | CTR_INTERRUPT_PREABRT, 31 | CTR_INTERRUPT_DATABRT, 32 | CTR_INTERRUPT_IRQ, 33 | CTR_INTERRUPT_FIQ 34 | } ctr_interrupt_enum; 35 | 36 | /** @brief Sets up the exception vectors in ITCM. 37 | * 38 | * For this function to work, ITCM must be enabled and MPU must allow for 39 | * writing and reading from 0x0000 to 0x8000. 40 | */ 41 | void ctr_interrupt_prepare(void); 42 | 43 | /** @brief Sets up a handler for the given exception. 44 | * 45 | * When the user-provided handler is called when an exception is generated, 46 | * the parameter given to the function is an array with the following data 47 | * from before the exception: 48 | * [ cpsr, sp, lr, return address, r0-r12 ] 49 | * 50 | * Note that lr is the lr prior to running handler. The return address is what 51 | * is stored by the CPU to LR when switching into the exception handler. Refer 52 | * to the ARM documentation to see how much the return address was modified 53 | * relative to the PC of when the exceptiin was triggered. Any changes to any 54 | * of the values in the input array WILL be written back to the corresponding 55 | * registers when the exception returns, if the handler returns. This can be 56 | * used to skip the instruction that caused a data abort, for example, by 57 | * editing the return address to skip it. Note that for return address 58 | * adjustments, the mode of execution when the exception was triggered is 59 | * important. Check the T bit of cpsr in the input array to determine the mode 60 | * of execution when the exception was thrown. 61 | * 62 | * @param[in] interrupt_type Enumeration determining which exception to set up. 63 | * @param[in] interrupt Handler to call when the exception is fired. The handler 64 | * can be either Thumb or ARM code. 65 | * @param[in,out] data Pointer to any kind of data, passed as is to the 66 | * interrupt handler when it is invoked. 67 | */ 68 | void ctr_interrupt_set(ctr_interrupt_enum interrupt_type, void (*interrupt)(uint32_t*, void*), void *data); 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif//CTR_INTERRUPT_H_ 75 | 76 | -------------------------------------------------------------------------------- /include/ctr9/ctr_pxi.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_PXI_H_ 12 | #define CTR_PXI_H_ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | //PXI registers 24 | #define PXI_SYNC9 PXI_SYNC((volatile uint32_t*)0x10008000) 25 | #define PXI_CNT9 PXI_CNT((volatile uint32_t*)0x10008000) 26 | #define PXI_SEND9 PXI_SEND((volatile uint32_t*)0x10008000) 27 | #define PXI_RECV9 PXI_RECV((volatile uint32_t*)0x10008000) 28 | 29 | /** @brief Initializes the PXI plumbing for libctr9. 30 | * 31 | * Make sure to call this before using any other libctr9 PXI function. 32 | */ 33 | void ctr_pxi_initialize(void); 34 | 35 | /** @brief Checks if the send PXI queue is empty. 36 | * 37 | * @returns True if the send PXI queue is empty, false otherwise. 38 | */ 39 | bool ctr_pxi_send_empty_status(void); 40 | 41 | /** @brief Checks if the send PXI queue is full. 42 | * 43 | * @returns True if the send PXI queue is full, false otherwise. 44 | */ 45 | bool ctr_pxi_send_full_status(void); 46 | 47 | /** @brief Checks the status of the IRQ for when the send PXI queue is empty. 48 | * 49 | * @returns True if the IRQ is enabled, false otherwise. 50 | */ 51 | bool ctr_pxi_get_send_empty_irq(void); 52 | 53 | /** @brief Sets the state of the IRQ for when the send PXI queue is empty. 54 | * 55 | * @param[in] state The state to set the IRQ to, true to enable, false to 56 | * disable. 57 | * 58 | * @post The IRQ will be enabled if thet parameter is true, or disabled if 59 | * false. 60 | */ 61 | void ctr_pxi_set_send_empty_irq(bool state); 62 | 63 | /** @brief Clears/flushes the send PXI queue. 64 | * 65 | * @post Clears/flushes the send PXI queue. 66 | */ 67 | void ctr_pxi_fifo_send_clear(void); 68 | 69 | /** @brief Checks if the receive PXI queue is empty. 70 | * 71 | * @returns True if the receive PXI queue is empty, false otherwise. 72 | */ 73 | bool ctr_pxi_receive_empty_status(void); 74 | 75 | /** @brief Checks if the receive PXI queue is full. 76 | * 77 | * @returns True if the receive PXI queue is full, false otherwise. 78 | */ 79 | bool ctr_pxi_receive_full_status(void); 80 | 81 | /** @brief Checks the status of the IRQ for when the receive PXI queue is not 82 | * empty. 83 | * 84 | * @returns True if the IRQ is enabled, false otherwise. 85 | */ 86 | bool ctr_pxi_get_receive_not_empty_irq(void); 87 | 88 | /** @brief Sets the state of the IRQ for when the receive PXI queue is not empty. 89 | * 90 | * @param[in] state The state to set the IRQ to, true to enable, false to 91 | * disable. 92 | * 93 | * @post The IRQ will be enabled if thet parameter is true, or disabled if 94 | * false. 95 | */ 96 | void ctr_pxi_set_receive_not_empty_irq(bool state); 97 | 98 | /** @brief Sets the state of the PXI system. 99 | * 100 | * @param[in] state State to set the PXI system to. 101 | * 102 | * @post On setting the state to true, the PXI system is enabled. On false it 103 | * is disabled. 104 | */ 105 | void ctr_pxi_set_enabled(bool state); 106 | 107 | /** @brief Returns the state of the PXI system. 108 | * 109 | * @brief Returns true if the PXI system is enabled, false otherwise. 110 | */ 111 | bool ctr_pxi_get_enabled(void); 112 | 113 | /** @brief (FIXME Uncertain, this is most likely wrong) Acknowledge IRQ. 114 | */ 115 | void ctr_pxi_fifo_ack(void); 116 | 117 | /** @brief Returns the error status of the PXI system. 118 | * 119 | * An error is set when a read is attempted from the read PXI queue and there 120 | * is no data there, or when data is attempted to be sent when the send PXI 121 | * queue is full. No errors are set when the system if offline. 122 | * 123 | * @returns True if an error is reported by the PXI system, false otherwise. 124 | */ 125 | bool ctr_pxi_get_error(void); 126 | 127 | /** @brief Push data into the send PXI queue. 128 | * 129 | * @param[in] data Data to push into send PXI queue. 130 | * 131 | * @returns True if pushing succeeded, false if the queue was full and the push 132 | * failed. 133 | */ 134 | bool ctr_pxi_push(uint32_t data); 135 | 136 | /** @brief Pops data from the receive PXI queue. 137 | * 138 | * @param[in] data Pointer to where to store data popped from the receive PXI 139 | * queue. 140 | * 141 | * @returns True if popping succeeded, false if the queue was empty and the 142 | * pop failed. 143 | */ 144 | bool ctr_pxi_pop(uint32_t *data); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif//CTR_PXI_H_ 151 | 152 | -------------------------------------------------------------------------------- /include/ctr9/ctr_rtc.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_RTC_H_ 12 | #define CTR_RTC_H_ 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /** @brief Represents the RTC data returned by the RTC hardware. 21 | */ 22 | typedef struct 23 | { 24 | uint8_t seconds, minutes, hours, pad_, day, month, year; 25 | } ctr_rtc_data; 26 | 27 | /** @brief Initializes the data used for RTC access. 28 | * 29 | * Call this function at least once before trying to get the RTC time. It is 30 | * safe to call this function multiple times. 31 | */ 32 | void ctr_rtc_init(void); 33 | 34 | /** @brief Returns the data read from the RTC. 35 | * 36 | * The underlying RTC returns data in BCD format, but this function converts 37 | * the BCD to binary. 38 | * 39 | * @pre ctr_rtc_init has been called at least once. 40 | * @returns The binary representation of the RTC BCD data. 41 | */ 42 | ctr_rtc_data ctr_rtc_gettime(void); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif//CTR_RTC_H_ 49 | 50 | -------------------------------------------------------------------------------- /include/ctr9/ctr_system.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_SYSTEM_H_ 12 | #define CTR_SYSTEM_H_ 13 | 14 | #include 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** @brief Enumeration describing the running system. 23 | */ 24 | typedef ctr_core_system_type ctr_system_type; 25 | 26 | /** @brief Returns whether the arm9 entry was a9lh or not. 27 | * 28 | * @returns True if the arm9 entrypoint was a9lh, false otherwise. 29 | */ 30 | bool ctr_detect_a9lh_entry(void); 31 | 32 | /** @brief Sets up the TWL keyslot. 33 | * 34 | * This only really matters if arm9 execution is obtained via a9lh, or prior to 35 | * a FIRM load. Nothing happens if FIRM had been launched previously. 36 | * 37 | * @pre The areas of ITCM with TWL information are intact. 38 | * @post TWL keys are setup. Note that this also does use the SHA subsystem, so 39 | * the SHA register is modified. This means that under a9lh this overwrites 40 | * the OTP hash, so back it up before calling this function. 41 | * 42 | * @post The TWL keyslot is setup properly. 43 | */ 44 | void ctr_twl_keyslot_setup(void); 45 | 46 | /** @brief Powers off the 3DS. 47 | * 48 | * This function does not return. It powers off the 3DS via an i2c call to the 49 | * MPU. 50 | * 51 | * @post 3DS has powered off. 52 | */ 53 | void ctr_system_poweroff(void); 54 | 55 | /** @brief Resets the 3DS. 56 | * 57 | * This function does not return. It resets the 3DS via an i2c call to the MPU. 58 | * 59 | * @post 3DS has restarted. 60 | */ 61 | void ctr_system_reset(void); 62 | 63 | /** @brief Returns the enumeration corresponding to the running system. 64 | * 65 | * @returns The type of system this is called in. 66 | */ 67 | ctr_system_type ctr_get_system_type(void); 68 | 69 | /** @brief Sets up the keyslot required for N3DS CTRNAND access. 70 | * 71 | * @post Possible to use keyslot 0x5 to decrypt N3DS CTRNAND. 72 | */ 73 | void ctr_n3ds_ctrnand_keyslot_setup(void); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif//CTR_SYSTEM_H_ 80 | 81 | -------------------------------------------------------------------------------- /include/ctr9/ctr_system_clock.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_SYSTEM_CLOCK_H_ 12 | #define CTR_SYSTEM_CLOCK_H_ 13 | 14 | #include 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /** @brief Represents the clock internal data. 22 | */ 23 | typedef struct 24 | { 25 | uint64_t count; 26 | ctr_timer timer; 27 | } ctr_system_clock; 28 | 29 | /** @brief Represents a detailed time structure used by the system clock. 30 | */ 31 | typedef struct 32 | { 33 | int64_t seconds; 34 | int32_t nanoseconds; 35 | } ctr_clock_time; 36 | 37 | /** @brief Initializes a clock, taking control of the specified timer. 38 | * 39 | * Once initialized, the system clock overrides whatever settings the 40 | * timer was set to. In order for the clock to work, global IRQs must 41 | * be enabled. 42 | * 43 | * @param[out] clock Pointer to clock data structure to initialize. 44 | * @param[in[ timer Timer to take control over. 45 | * 46 | */ 47 | void ctr_system_clock_initialize(ctr_system_clock *clock, ctr_timer timer); 48 | 49 | /** @brief Returns the number of milliseconds that have passed since the clock 50 | * started. 51 | * 52 | * @param[in] clock Pointer to the clock to query. 53 | * 54 | * @returns The number of milliseconds that have passed since the clock 55 | * started. 56 | */ 57 | uint64_t ctr_system_clock_get_ms(ctr_system_clock *clock); 58 | 59 | /** @brief Returns a detailed time structure representing the amount of time 60 | * that has passed since the clock was started. 61 | * 62 | * @param[in] clock Pointer to the clock to query. 63 | * 64 | * @returns A detailed time structure representing the amount of time that 65 | * has passed since the clock was started. 66 | */ 67 | ctr_clock_time ctr_system_clock_get_time(ctr_system_clock *clock); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif//CTR_SYSTEM_CLOCK_H_ 74 | 75 | -------------------------------------------------------------------------------- /include/ctr9/gamecart/command_ctr.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void CTR_CmdReadSectorSD(uint8_t* aBuffer, uint32_t aSector); 14 | void CTR_CmdReadData(uint32_t sector, uint32_t length, uint32_t blocks, void* buffer); 15 | void CTR_CmdReadHeader(void* buffer); 16 | uint32_t CTR_CmdGetSecureId(uint32_t rand1, uint32_t rand2); 17 | void CTR_CmdSeed(uint32_t rand1, uint32_t rand2); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | -------------------------------------------------------------------------------- /include/ctr9/gamecart/command_ntr.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void NTR_CmdReset(void); 14 | uint32_t NTR_CmdGetCartId(void); 15 | void NTR_CmdEnter16ByteMode(void); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | -------------------------------------------------------------------------------- /include/ctr9/gamecart/protocol.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define REG_CARDCONF (*(volatile uint16_t*)0x1000000C) 13 | #define REG_CARDCONF2 (*(volatile uint8_t*)0x10000010) 14 | 15 | //REG_AUXSPICNT 16 | #define CARD_ENABLE (1u<<15) 17 | #define CARD_SPI_ENABLE (1u<<13) 18 | #define CARD_SPI_BUSY (1u<<7) 19 | #define CARD_SPI_HOLD (1u<<6) 20 | 21 | #define LATENCY 0x822Cu 22 | 23 | uint32_t BSWAP32(uint32_t val); 24 | 25 | void Cart_Init(void); 26 | int Cart_IsInserted(void); 27 | uint32_t Cart_GetID(void); 28 | void Cart_Secure_Init(uint32_t* buf, uint32_t* out); 29 | void Cart_Dummy(void); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | 36 | -------------------------------------------------------------------------------- /include/ctr9/gamecart/protocol_ctr.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define REG_CTRCARDCNT (*(volatile uint32_t*)0x10004000) 15 | #define REG_CTRCARDBLKCNT (*(volatile uint32_t*)0x10004004) 16 | #define REG_CTRCARDSECCNT (*(volatile uint32_t*)0x10004008) 17 | #define REG_CTRCARDSECSEED (*(volatile uint32_t*)0x10004010) 18 | #define REG_CTRCARDCMD ((volatile uint32_t*)0x10004020) 19 | #define REG_CTRCARDFIFO (*(volatile uint32_t*)0x10004030) 20 | 21 | #define CTRCARD_PAGESIZE_0 (0<<16) 22 | #define CTRCARD_PAGESIZE_4 (1u<<16) 23 | #define CTRCARD_PAGESIZE_16 (2u<<16) 24 | #define CTRCARD_PAGESIZE_64 (3u<<16) 25 | #define CTRCARD_PAGESIZE_512 (4u<<16) 26 | #define CTRCARD_PAGESIZE_1K (5u<<16) 27 | #define CTRCARD_PAGESIZE_2K (6u<<16) 28 | #define CTRCARD_PAGESIZE_4K (7u<<16) 29 | #define CTRCARD_PAGESIZE_16K (8u<<16) 30 | #define CTRCARD_PAGESIZE_64K (9u<<16) 31 | 32 | #define CTRCARD_CRC_ERROR (1u<<4) 33 | #define CTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling 34 | #define CTRCARD_IE (1u<<30) // Interrupt enable 35 | #define CTRCARD_WR (1u<<29) // Card write enable 36 | #define CTRCARD_nRESET (1u<<28) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) 37 | #define CTRCARD_BLK_SIZE(n) (((n)&0xFu)<<16) // Transfer block size 38 | 39 | #define CTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? 40 | #define CTRCARD_DATA_READY (1u<<27) // when reading, REG_CTRCARDFIFO has another word of data and is good to go 41 | 42 | #define CTRKEY_PARAM 0x1000000u 43 | 44 | void CTR_SetSecKey(uint32_t value); 45 | void CTR_SetSecSeed(const uint32_t* seed, bool flag); 46 | 47 | void CTR_SendCommand(const uint32_t command[4], uint32_t pageSize, uint32_t blocks, uint32_t latency, void* buffer); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /include/ctr9/gamecart/protocol_ntr.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define REG_NTRCARDMCNT (*(volatile uint16_t*)0x10164000) 14 | #define REG_NTRCARDMDATA (*(volatile uint16_t*)0x10164002) 15 | #define REG_NTRCARDROMCNT (*(volatile uint32_t*)0x10164004) 16 | #define REG_NTRCARDCMD ((volatile uint8_t*)0x10164008) 17 | #define REG_NTRCARDSEEDX_L (*(volatile uint32_t*)0x10164010) 18 | #define REG_NTRCARDSEEDY_L (*(volatile uint32_t*)0x10164014) 19 | #define REG_NTRCARDSEEDX_H (*(volatile uint16_t*)0x10164018) 20 | #define REG_NTRCARDSEEDY_H (*(volatile uint16_t*)0x1016401A) 21 | #define REG_NTRCARDFIFO (*(volatile uint32_t*)0x1016401C) 22 | 23 | #define NTRCARD_PAGESIZE_0 (0<<24) 24 | #define NTRCARD_PAGESIZE_4 (7u<<24) 25 | #define NTRCARD_PAGESIZE_512 (1u<<24) 26 | #define NTRCARD_PAGESIZE_1K (2u<<24) 27 | #define NTRCARD_PAGESIZE_2K (3u<<24) 28 | #define NTRCARD_PAGESIZE_4K (4u<<24) 29 | #define NTRCARD_PAGESIZE_8K (5u<<24) 30 | #define NTRCARD_PAGESIZE_16K (6u<<24) 31 | 32 | #define NTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling 33 | #define NTRCARD_WR (1u<<30) // Card write enable 34 | #define NTRCARD_nRESET (1u<<29) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) 35 | #define NTRCARD_SEC_LARGE (1u<<28) // Use "other" secure area mode, which tranfers blocks of 0x1000 bytes at a time 36 | #define NTRCARD_CLK_SLOW (1u<<27) // Transfer clock rate (0 = 6.7MHz, 1 = 4.2MHz) 37 | #define NTRCARD_BLK_SIZE(n) (((n)&0x7u)<<24) // Transfer block size, (0 = None, 1..6 = (0x100 << n) bytes, 7 = 4 bytes) 38 | #define NTRCARD_SEC_CMD (1u<<22) // The command transfer will be hardware encrypted (KEY2) 39 | #define NTRCARD_DELAY2(n) (((n)&0x3Fu)<<16) // Transfer delay length part 2 40 | #define NTRCARD_SEC_SEED (1u<<15) // Apply encryption (KEY2) seed to hardware registers 41 | #define NTRCARD_SEC_EN (1u<<14) // Security enable 42 | #define NTRCARD_SEC_DAT (1u<<13) // The data transfer will be hardware encrypted (KEY2) 43 | #define NTRCARD_DELAY1(n) ((n)&0x1FFFu) // Transfer delay length part 1 44 | 45 | // 3 bits in b10..b8 indicate something 46 | // read bits 47 | #define NTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? 48 | #define NTRCARD_DATA_READY (1u<<23) // when reading, REG_NTRCARDFIFO has another word of data and is good to go 49 | 50 | // Card commands 51 | #define NTRCARD_CMD_DUMMY 0x9Fu 52 | #define NTRCARD_CMD_HEADER_READ 0x00u 53 | #define NTRCARD_CMD_HEADER_CHIPID 0x90u 54 | #define NTRCARD_CMD_ACTIVATE_BF 0x3Cu // Go into blowfish (KEY1) encryption mode 55 | #define NTRCARD_CMD_ACTIVATE_SEC 0x40u // Go into hardware (KEY2) encryption mode 56 | #define NTRCARD_CMD_SECURE_CHIPID 0x10u 57 | #define NTRCARD_CMD_SECURE_READ 0x20u 58 | #define NTRCARD_CMD_DISABLE_SEC 0x60u // Leave hardware (KEY2) encryption mode 59 | #define NTRCARD_CMD_DATA_MODE 0xA0u 60 | #define NTRCARD_CMD_DATA_READ 0xB7u 61 | #define NTRCARD_CMD_DATA_CHIPID 0xB8u 62 | 63 | #define NTRCARD_CR1_ENABLE 0x8000u 64 | #define NTRCARD_CR1_IRQ 0x4000u 65 | 66 | #define NTRKEY_PARAM 0x3F1FFFu 67 | 68 | void NTR_SendCommand(const uint32_t command[2], uint32_t pageSize, uint32_t latency, void* buffer); 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | -------------------------------------------------------------------------------- /include/ctr9/i2c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define I2C1_REG_OFF 0x10161000 14 | #define I2C2_REG_OFF 0x10144000 15 | #define I2C3_REG_OFF 0x10148000 16 | 17 | #define I2C_REG_DATA 0 18 | #define I2C_REG_CNT 1 19 | #define I2C_REG_CNTEX 2 20 | #define I2C_REG_SCL 4 21 | 22 | #define I2C_DEV_MCU 3 23 | #define I2C_DEV_GYRO 10 24 | #define I2C_DEV_IR 13 25 | 26 | uint8_t i2cGetDeviceBusId(uint8_t device_id); 27 | uint8_t i2cGetDeviceRegAddr(uint8_t device_id); 28 | 29 | volatile uint8_t* i2cGetDataReg(uint8_t bus_id); 30 | volatile uint8_t* i2cGetCntReg(uint8_t bus_id); 31 | 32 | void i2cWaitBusy(uint8_t bus_id); 33 | bool i2cGetResult(uint8_t bus_id); 34 | uint8_t i2cGetData(uint8_t bus_id); 35 | void i2cStop(uint8_t bus_id, uint8_t arg0); 36 | 37 | bool i2cSelectDevice(uint8_t bus_id, uint8_t dev_reg); 38 | bool i2cSelectRegister(uint8_t bus_id, uint8_t reg); 39 | 40 | uint8_t i2cReadRegister(uint8_t dev_id, uint8_t reg); 41 | bool i2cWriteRegister(uint8_t dev_id, uint8_t reg, uint8_t data); 42 | 43 | bool i2cReadRegisterBuffer(uint8_t dev_id, uint8_t reg, uint8_t *buffer, size_t buf_size); 44 | bool i2cWriteRegisterBuffer(uint8_t dev_id, uint8_t reg, const uint8_t *buffer, size_t buf_size); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /include/ctr9/io.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #ifndef CTR_IO_H_ 10 | #define CTR_IO_H_ 11 | 12 | #include "io/ctr_io_interface.h" 13 | #include "io/ctr_nand_interface.h" 14 | #include "io/ctr_nand_crypto_interface.h" 15 | #include "io/ctr_sd_interface.h" 16 | #include "io/ctr_file_interface.h" 17 | #include "io/ctr_disks.h" 18 | #include "io/ctr_cart_interface.h" 19 | #include "io/ctr_memory_interface.h" 20 | #include "io/ctr_crypto_interface.h" 21 | 22 | #endif//CTR_IO_H_ 23 | 24 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_console.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_CONSOLE_H_ 12 | #define CTR_CONSOLE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /** @brief Initializes the console subsystem. 26 | * 27 | * @returns 0 on success, anything else on an error. This function should 28 | * suceed. If it does not, this means that the underling libc and graphics 29 | * handling for libctr9 is broken. 30 | */ 31 | int ctr_console_initialize(const ctr_screen *screen); 32 | 33 | typedef ctr_core_console ctr_console; 34 | 35 | void ctr_console_draw(char c); 36 | short ctr_console_get_char_width(char c); 37 | unsigned int ctr_console_get_char_height(void); 38 | void ctr_console_clear(void); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif//CTR_CONSOLE_H_ 45 | 46 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_disks.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_DISKS_H_ 12 | #define CTR_DISKS_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** @brief Convenience function to help initialize the IO interfaces commonly 23 | * used in 3DS applications. 24 | * 25 | * @param[out] nand_io Pointer to nand_io to initialize. This will set up the 26 | * interface to access NAND generally. If NULL, this parameter is ignored. 27 | * Note that if this parameter is NULL, ctr_io and twl_io must also be 28 | * NULL since they depend on nand_io. 29 | * @param[out] ctr_io Pointer to nand_io to initialize. This will set up the 30 | * interface for CTRNAND decryption and encryption, using nand_io as the 31 | * base layer. If NULL, this parameter is ignored. 32 | * @param[out] twl_io Pointer to nand_io to initialize. This will set up the 33 | * interface for TWL* decryption and encryption, using nand_io as the base 34 | * layer. If NULL, this parameter is ignored. 35 | * @param[out] sd_io Pointer to nand_io to initialize. This will set up the 36 | * interface to access the SD card generally. If NULL, this parameter is 37 | * ignored. 38 | * 39 | * @return 0 on success, anything else if there was a problem initializing any 40 | * of the layers requested. 41 | */ 42 | int ctr_disks_initialize( 43 | ctr_nand_interface *nand_io, 44 | ctr_nand_crypto_interface *ctr_io, 45 | ctr_nand_crypto_interface *twl_io, 46 | ctr_sd_interface *sd_io); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif//CTR_DISKS_H_ 53 | 54 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_drives.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_DRIVES_H_ 12 | #define CTR_DRIVES_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /** @brief Initializes the standard library IO FILE subsystem. 19 | * 20 | * @returns 0 on success, anything else on an error. 21 | */ 22 | int ctr_drives_initialize(void); 23 | 24 | /** @brief Checks whether the given drive is ready. 25 | * 26 | * Possible drives are: 27 | * "CTRNAND:" 28 | * "SD:" 29 | * "TWLN:" 30 | * "TWLP:" 31 | * "DISK0:" 32 | * "DISK1:" 33 | * "DISK2:" 34 | * "DISK3:" 35 | * "DISK4:" 36 | * "DISK5:" 37 | * 38 | * @param[in] Drive path to check if it is ready or not. 39 | * 40 | * @returns 0 on success, anything else for an error indicating the drive is 41 | * not ready for access via FILE functions. 42 | */ 43 | int ctr_drives_check_ready(const char *drive); 44 | 45 | /** @brief Changes the default drive used when no drive is specified in the 46 | * path. 47 | * 48 | * @param[in] drive Drive path to set as the default. See 49 | * ctr_drives_check_ready for a list of drives supported. 50 | * 51 | * @returns 0 on success, anything else on an error. 52 | */ 53 | int ctr_drives_chdrive(const char *drive); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif//CTR_DRIVES_H_ 60 | 61 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_file_interface.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_FILE_INTERFACE_H_ 12 | #define CTR_FILE_INTERFACE_H_ 13 | 14 | #include "ctr_io_interface.h" 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /** @brief io interface object for accessing a file file as a disk. 22 | */ 23 | typedef struct 24 | { 25 | ctr_io_interface base; 26 | FILE *file; 27 | } ctr_file_interface; 28 | 29 | /** @brief Initialize the given file io interface object. 30 | * 31 | * Note that any size file greater or equal than a single sector will be 32 | * accepted by the constructor, but the io operations will ignore the trailing 33 | * data on the file if the file size isn't divisible by the sector size. In 34 | * other words, the effective size of the disk is fsize(file)/0x200, 35 | * using integer arithmetic. In order for reads to work the file must have been 36 | * opened using "rb", and for writes to work "r+b". 37 | * 38 | * @param[out] io file io interface to initialize. 39 | * @param[in,out] file File to set up as a disk. 40 | * 41 | * @returns 0 on success, anything else on a failure. 42 | */ 43 | int ctr_file_interface_initialize(ctr_file_interface *io, FILE *file); 44 | 45 | /** @brief Destroys the given file io interface object. 46 | * 47 | * @param[in,out] io file io interface to deinitialize. 48 | * 49 | * @post The io interface has been destroyed and cannot be used for accessing 50 | * the file file as a disk without being re-initialized. 51 | */ 52 | void ctr_file_interface_destroy(ctr_file_interface *io); 53 | 54 | /** @brief Reads bytes from the given io interface. 55 | * 56 | * @param[in,out] io The io interface to use for reading. 57 | * @param[out] buffer Pointer to the buffer. 58 | * @param[in] buffer_size The size of the buffer in bytes. 59 | * @param[in] position Position/address in the io interface to read from. 60 | * @param[in] count The number of bytes to read. 61 | * 62 | * @returns 0 upon success, anything else means an error. 63 | */ 64 | int ctr_file_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count); 65 | 66 | /** @brief Writes bytes to the given io interface. 67 | * 68 | * @param[in,out] io The io interface to use for writing. 69 | * @param[in] buffer Pointer to the buffer. 70 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 71 | * write. 72 | * @param[in] position Position/address in the io interface to write to. 73 | * 74 | * @returns 0 upon success, anything else means an error. 75 | */ 76 | int ctr_file_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position); 77 | 78 | /** @brief Reads sectors from the given io interface. 79 | * 80 | * file is configured to only use 512 byte sectors. 81 | * 82 | * @param[in,out] io The io interface to use for reading. 83 | * @param[out] buffer Pointer to the buffer. 84 | * @param[in] buffer_size The size of the buffer in bytes. 85 | * @param[in] sector Sector position in the io interface to read from. 86 | * @param[in] count The number of sectors to read. 87 | * 88 | * @returns 0 upon success, anything else means an error. 89 | */ 90 | int ctr_file_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count); 91 | 92 | /** @brief Writes sectors from the given io interface. 93 | * 94 | * file is configured to only use 512 byte sectors. 95 | * 96 | * @param[in,out] io The io interface to use for writing. 97 | * @param[in] buffer Pointer to the buffer. 98 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 99 | * write. If the number is not a multiple of the sector size, this function 100 | * will only write all the full sectors it can, ignoring the end of the 101 | * buffer that doesn't fit a sector. 102 | * @param[in] sector Sector Position in the io interface to write to. 103 | * 104 | * @returns 0 upon success, anything else means an error. 105 | */ 106 | int ctr_file_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector); 107 | 108 | /** @brief Returns the size of the underlying disk for the given io interface. 109 | * 110 | * @returns The size of the file used as the backing for the given io 111 | * interface. 112 | */ 113 | uint64_t ctr_file_interface_disk_size(void *io); 114 | 115 | /** @brief Returns the size of the sectors used by the io interface, which is 116 | * 512 bytes for file due to how it is configured. 117 | * 118 | * @returns 512 bytes as the sector size. 119 | */ 120 | size_t ctr_file_interface_sector_size(void *io); 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif//CTR_FILE_INTERFACE_H_ 127 | 128 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_io_implementation.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include "ctr_io_implementation.h" 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | static inline int ctr_io_implementation_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count, ctr_io_implementation_read_sector_f read) 17 | { 18 | int res = 0; 19 | if (count && buffer_size) 20 | { 21 | const size_t sector_size = ctr_io_sector_size(io); 22 | size_t total_readable = count < buffer_size ? count : buffer_size; 23 | 24 | uint8_t *dest = buffer; 25 | uint8_t buf[sector_size]; 26 | const size_t base_sector = position / sector_size; 27 | 28 | size_t bytes_read = 0; 29 | size_t sectors_read = 0; 30 | 31 | //Section 1: read first sector to extract the right number of bytes from it 32 | const size_t start_location = position % sector_size; 33 | res |= read(io, buf, sizeof(buf), base_sector, 1); 34 | if (res) return res; 35 | 36 | sectors_read++; 37 | 38 | size_t section_readable = sector_size - start_location; 39 | if (section_readable > total_readable) 40 | { 41 | section_readable = total_readable; 42 | } 43 | 44 | memcpy(dest, &buf[start_location], section_readable); 45 | bytes_read += section_readable; 46 | 47 | //Section 2: read all sectors until the last one 48 | section_readable = (total_readable - bytes_read); 49 | size_t mid_sectors = section_readable / sector_size; 50 | 51 | if (mid_sectors) 52 | { 53 | res |= read(io, dest + bytes_read, section_readable, base_sector + sectors_read, mid_sectors); 54 | if (res) return res; 55 | sectors_read += mid_sectors; 56 | bytes_read += mid_sectors * sector_size; 57 | } 58 | 59 | //Section 3: read last sector to extract the right number of bytes from it 60 | section_readable = total_readable - bytes_read; 61 | if (!res && section_readable) 62 | { 63 | res |= read(io, buf, sizeof(buf), base_sector + sectors_read, 1); 64 | if (res) return res; 65 | memcpy(dest + bytes_read, buf, section_readable); 66 | } 67 | } 68 | return res; 69 | } 70 | 71 | static inline int ctr_io_implementation_write(void *io, const void *buffer, size_t buffer_size, uint64_t position, ctr_io_implementation_read_sector_f read, ctr_io_implementation_write_sector_f write) 72 | { 73 | int res = 0; 74 | if (buffer_size) 75 | { 76 | const size_t sector_size = ctr_io_sector_size(io); 77 | const uint8_t *source = buffer; 78 | uint8_t buf[sector_size]; 79 | const size_t base_sector = position / sector_size; 80 | const size_t start_location = position % sector_size; 81 | 82 | size_t bytes_written = 0; 83 | size_t sectors_written = 0; 84 | 85 | //Section 1: read first sector to write back after adding the data to the sector 86 | res |= read(io, buf, sizeof(buf), base_sector, ++sectors_written); 87 | if (res) return res; 88 | 89 | const size_t writeable = sector_size - start_location; 90 | bytes_written += writeable < buffer_size ? writeable : buffer_size; 91 | 92 | memcpy(buf + start_location, source, bytes_written); 93 | res |= write(io, buf, sizeof(buf), base_sector); 94 | if (res) return res; 95 | 96 | const size_t mid_sectors = (buffer_size-bytes_written) / sector_size; 97 | //Section 2: write all sectors until the last one 98 | if (mid_sectors) 99 | { 100 | res |= write(io, source + bytes_written, buffer_size-bytes_written, base_sector + sectors_written); 101 | if (res) return res; 102 | sectors_written += mid_sectors; 103 | bytes_written += mid_sectors * sector_size; 104 | } 105 | 106 | //Section 3: read last sector to write back after adding the last bytes from the buffer 107 | if (bytes_written != buffer_size) 108 | { 109 | res |= read(io, buf, sizeof(buf), base_sector + sectors_written, 1); 110 | if (res) return res; 111 | memcpy(buf, source + bytes_written, buffer_size - bytes_written); 112 | write(io, buf, sizeof(buf), base_sector + sectors_written); 113 | } 114 | } 115 | return res; 116 | } 117 | 118 | #ifdef __cplusplus 119 | } 120 | #endif 121 | 122 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_io_implementation.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_IO_IMPLEMENTATION_H_ 12 | #define CTR_IO_IMPLEMENTATION_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /** @brief Pointer to an io interface function for reading sectors. 19 | * 20 | * @param[out] buffer Pointer to the buffer. 21 | * @param[in] buffer_size The size of the buffer in bytes. 22 | * @param[in] sector Sector position in the io interface to read from. 23 | * @param[in] count The number of sectors to read. 24 | * @param[in] read Pointer to sdmmc function to read sectors. 25 | * 26 | * @returns 0 upon success, anything else means an error. 27 | */ 28 | typedef int (*ctr_io_implementation_read_sector_f)(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count); 29 | 30 | /** @brief Pointer to an io interface function for writing to sectors. 31 | * 32 | * @param[in] buffer Pointer to the buffer. 33 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 34 | * write. If the number is not a multiple of the sector size, this function 35 | * will only write all the full sectors it can, ignoring the end of the 36 | * buffer that doesn't fit a sector. 37 | * @param[in] sector Sector Position in the io interface to write to. 38 | * @param[in] write Pointer to sdmmc function to write sectors. 39 | * 40 | * @returns 0 upon success, anything else means an error. 41 | */ 42 | 43 | typedef int (*ctr_io_implementation_write_sector_f)(void *io, const void *buffer, size_t buffer_size, size_t sector); 44 | 45 | /** @brief General implementation for reading bytes using a general io sector 46 | * function. 47 | * 48 | * @param[out] buffer Pointer to the buffer. 49 | * @param[in] buffer_size The size of the buffer in bytes. 50 | * @param[in] position Position/address in the io interface to read from. 51 | * @param[in] count The number of bytes to read. 52 | * @param[in] read Pointer to sdmmc function to read sectors. 53 | * 54 | * @returns 0 upon success, anything else means an error. 55 | */ 56 | static inline int ctr_io_implementation_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count, ctr_io_implementation_read_sector_f read); 57 | 58 | /** @brief General implementation for writing bytes using a general io sector 59 | * function. 60 | * 61 | * @param[in] buffer Pointer to the buffer. 62 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 63 | * write. 64 | * @param[in] position Position/address in the io interface to write to. 65 | * @param[in] read Pointer to sdmmc function to read sectors. 66 | * @param[in] write Pointer to sdmmc function to write sectors. 67 | * 68 | * @returns 0 upon success, anything else means an error. 69 | */ 70 | static inline int ctr_io_implementation_write(void *io, const void *buffer, size_t buffer_size, uint64_t position, ctr_io_implementation_read_sector_f read, ctr_io_implementation_write_sector_f write); 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #include "ctr_io_implementation.c" 77 | 78 | #endif//CTR_IO_IMPLEMENTATION_H_ 79 | 80 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_memory_interface.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_MEMORY_INTERFACE_H_ 12 | #define CTR_MEMORY_INTERFACE_H_ 13 | 14 | #include "ctr_io_interface.h" 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /** @brief io interface object for accessing the memory. 22 | */ 23 | typedef struct 24 | { 25 | ctr_io_interface base; 26 | void *buffer; 27 | size_t buffer_size; 28 | } ctr_memory_interface; 29 | 30 | /** @brief Initialize the given memory io interface object. 31 | * 32 | * @param[out] io memory io interface to initialize. 33 | * @param[in] buffer Pointer to buffer to use as a disk. 34 | * @param[in] buffer_size Size of the buffer to be used as a disk. 35 | * 36 | * @post io is initialized and ready to be used in other ctr_memory_interface 37 | * functions. 38 | */ 39 | void ctr_memory_interface_initialize(ctr_memory_interface *io, void *buffer, size_t buffer_size); 40 | 41 | /** @brief Destroys the given memory io interface object. 42 | * 43 | * @param[in,out] io memory io interface to deinitialize. 44 | * 45 | * @post The io interface has been destroyed and cannot be used for accessing 46 | * the memory without being re-initialized. 47 | */ 48 | void ctr_memory_interface_destroy(ctr_memory_interface *io); 49 | 50 | /** @brief Reads bytes from the given io interface. 51 | * 52 | * @param[in,out] io The io interface to use for reading. 53 | * @param[out] buffer Pointer to the buffer. 54 | * @param[in] buffer_size The size of the buffer in bytes. 55 | * @param[in] position Position/address in the io interface to read from. 56 | * @param[in] count The number of bytes to read. 57 | * 58 | * @returns 0 upon success, anything else means an error. 59 | */ 60 | int ctr_memory_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count); 61 | 62 | /** @brief Writes bytes to the given io interface. 63 | * 64 | * @param[in,out] io The io interface to use for writing. 65 | * @param[in] buffer Pointer to the buffer. 66 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 67 | * write. 68 | * @param[in] position Position/address in the io interface to write to. 69 | * 70 | * @returns 0 upon success, anything else means an error. 71 | */ 72 | int ctr_memory_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position); 73 | 74 | /** @brief Reads sectors from the given io interface. 75 | * 76 | * Memory has no concept of sectors, so logical "sectors" are 1 byte. 77 | * 78 | * @param[in,out] io The io interface to use for reading. 79 | * @param[out] buffer Pointer to the buffer. 80 | * @param[in] buffer_size The size of the buffer in bytes. 81 | * @param[in] sector Sector position in the io interface to read from. 82 | * @param[in] count The number of sectors to read. 83 | * 84 | * @returns 0 upon success, anything else means an error. 85 | */ 86 | int ctr_memory_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count); 87 | 88 | /** @brief Writes sectors from the given io interface. 89 | * 90 | * Memory has no concept of sectors, so logical "sectors" are 1 byte. 91 | * 92 | * @param[in,out] io The io interface to use for writing. 93 | * @param[in] buffer Pointer to the buffer. 94 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 95 | * write. If the number is not a multiple of the sector size, this function 96 | * will only write all the full sectors it can, ignoring the end of the 97 | * buffer that doesn't fit a sector. 98 | * @param[in] sector Sector Position in the io interface to write to. 99 | * 100 | * @returns 0 upon success, anything else means an error. 101 | */ 102 | int ctr_memory_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sectorn); 103 | 104 | /** @brief Returns the size of the underlying disk for the given io interface. 105 | * 106 | * @returns The size of the memory buffer used by this io interface. 107 | */ 108 | uint64_t ctr_memory_interface_disk_size(void *io); 109 | 110 | /** @brief Returns the size of the sectors used by the io interface, which is 111 | * 1 bytes for memory. 112 | * 113 | * @returns 1 byte as the sector size for memorys. 114 | */ 115 | size_t ctr_memory_interface_sector_size(void *io); 116 | 117 | #ifdef __cplusplus 118 | } 119 | #endif 120 | 121 | #endif//CTR_MEMORY_INTERFACE_H_ 122 | 123 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_nand_interface.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_NAND_INTERFACE_H_ 12 | #define CTR_NAND_INTERFACE_H_ 13 | 14 | #include "ctr_io_interface.h" 15 | #include "sdmmc/sdmmc.h" 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | /** @brief io interface object for accessing NAND. 22 | */ 23 | typedef struct 24 | { 25 | ctr_io_interface base; 26 | } ctr_nand_interface; 27 | 28 | /** @brief Initialize the given NAND io interface object. 29 | * 30 | * @param[out] io NAND io interface to initialize. 31 | * 32 | * @returns 0 on success, anything else on a failure. Unless something has gone 33 | * horribly wrong with the NAND subsystem, this function shouldn't fail. 34 | */ 35 | int ctr_nand_interface_initialize(ctr_nand_interface *io); 36 | 37 | /** @brief Destroys the given NAND io interface object. 38 | * 39 | * @param[in,out] io NAND io interface to deinitialize. 40 | * 41 | * @post The io interface has been destroyed and cannot be used for accessing 42 | * NAND without being re-initialized. 43 | */ 44 | void ctr_nand_interface_destroy(ctr_nand_interface *io); 45 | 46 | /** @brief Reads bytes from the given io interface. 47 | * 48 | * @param[in,out] io The io interface to use for reading. 49 | * @param[out] buffer Pointer to the buffer. 50 | * @param[in] buffer_size The size of the buffer in bytes. 51 | * @param[in] position Position/address in the io interface to read from. 52 | * @param[in] count The number of bytes to read. 53 | * 54 | * @returns 0 upon success, anything else means an error. 55 | */ 56 | int ctr_nand_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count); 57 | 58 | /** @brief Writes bytes to the given io interface. 59 | * 60 | * @param[in,out] io The io interface to use for writing. 61 | * @param[in] buffer Pointer to the buffer. 62 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 63 | * write. 64 | * @param[in] position Position/address in the io interface to write to. 65 | * 66 | * @returns 0 upon success, anything else means an error. 67 | */ 68 | int ctr_nand_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position); 69 | 70 | /** @brief Reads sectors from the given io interface. 71 | * 72 | * NAND uses 512 byte sectors. 73 | * 74 | * @param[in,out] io The io interface to use for reading. 75 | * @param[out] buffer Pointer to the buffer. 76 | * @param[in] buffer_size The size of the buffer in bytes. 77 | * @param[in] sector Sector position in the io interface to read from. 78 | * @param[in] count The number of sectors to read. 79 | * 80 | * @returns 0 upon success, anything else means an error. 81 | */ 82 | int ctr_nand_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count); 83 | 84 | /** @brief Writes sectors from the given io interface. 85 | * 86 | * NAND uses 512 byte sectors. 87 | * 88 | * @param[in,out] io The io interface to use for writing. 89 | * @param[in] buffer Pointer to the buffer. 90 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 91 | * write. If the number is not a multiple of the sector size, this function 92 | * will only write all the full sectors it can, ignoring the end of the 93 | * buffer that doesn't fit a sector. 94 | * @param[in] sector Sector Position in the io interface to write to. 95 | * 96 | * @returns 0 upon success, anything else means an error. 97 | */ 98 | int ctr_nand_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector); 99 | 100 | /** @brief Returns the size of the underlying disk for the given io interface. 101 | * 102 | * @returns The size of the NAND as reported by it. 103 | */ 104 | uint64_t ctr_nand_interface_disk_size(void *io); 105 | 106 | /** @brief Returns the size of the sectors used by the io interface, which is 107 | * 512 bytes for NAND. 108 | * 109 | * @returns 512 bytes as the sector size for NAND. 110 | */ 111 | size_t ctr_nand_interface_sector_size(void *io); 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | 117 | #endif//CTR_NAND_INTERFACE_H_ 118 | 119 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_sd_interface.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_SD_INTERFACE_H_ 12 | #define CTR_SD_INTERFACE_H_ 13 | 14 | #include "ctr_io_interface.h" 15 | #include "sdmmc/sdmmc.h" 16 | 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** @brief io interface object for accessing the SD card. 24 | */ 25 | typedef struct 26 | { 27 | ctr_io_interface base; 28 | } ctr_sd_interface; 29 | 30 | /** @brief Initialize the given SD io interface object. 31 | * 32 | * @param[out] io SD io interface to initialize. 33 | * 34 | * @returns 0 on success, anything else on a failure. Failures can stem from 35 | * the SD card not being inserted, or some more severe underlying problem. 36 | */ 37 | int ctr_sd_interface_initialize(ctr_sd_interface *io); 38 | 39 | /** @brief Destroys the given SD io interface object. 40 | * 41 | * @param[in,out] io SD io interface to deinitialize. 42 | * 43 | * @post The io interface has been destroyed and cannot be used for accessing 44 | * the SD card without being re-initialized. 45 | */ 46 | void ctr_sd_interface_destroy(ctr_sd_interface *io); 47 | 48 | /** @brief Reads bytes from the given io interface. 49 | * 50 | * @param[in,out] io The io interface to use for reading. 51 | * @param[out] buffer Pointer to the buffer. 52 | * @param[in] buffer_size The size of the buffer in bytes. 53 | * @param[in] position Position/address in the io interface to read from. 54 | * @param[in] count The number of bytes to read. 55 | * 56 | * @returns 0 upon success, anything else means an error. 57 | */ 58 | int ctr_sd_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count); 59 | 60 | /** @brief Writes bytes to the given io interface. 61 | * 62 | * @param[in,out] io The io interface to use for writing. 63 | * @param[in] buffer Pointer to the buffer. 64 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 65 | * write. 66 | * @param[in] position Position/address in the io interface to write to. 67 | * 68 | * @returns 0 upon success, anything else means an error. 69 | */ 70 | int ctr_sd_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position); 71 | 72 | /** @brief Reads sectors from the given io interface. 73 | * 74 | * SD card access uses 512 byte sectors. 75 | * 76 | * @param[in,out] io The io interface to use for reading. 77 | * @param[out] buffer Pointer to the buffer. 78 | * @param[in] buffer_size The size of the buffer in bytes. 79 | * @param[in] sector Sector position in the io interface to read from. 80 | * @param[in] count The number of sectors to read. 81 | * 82 | * @returns 0 upon success, anything else means an error. 83 | */ 84 | int ctr_sd_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count); 85 | 86 | /** @brief Writes sectors from the given io interface. 87 | * 88 | * SD card access uses 512 byte sectors. 89 | * 90 | * @param[in,out] io The io interface to use for writing. 91 | * @param[in] buffer Pointer to the buffer. 92 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 93 | * write. If the number is not a multiple of the sector size, this function 94 | * will only write all the full sectors it can, ignoring the end of the 95 | * buffer that doesn't fit a sector. 96 | * @param[in] sector Sector Position in the io interface to write to. 97 | * 98 | * @returns 0 upon success, anything else means an error. 99 | */ 100 | int ctr_sd_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sectorn); 101 | 102 | /** @brief Returns the size of the underlying disk for the given io interface. 103 | * 104 | * @returns The size of the NAND as reported by it. 105 | */ 106 | uint64_t ctr_sd_interface_disk_size(void *io); 107 | 108 | /** @brief Returns the size of the sectors used by the io interface, which is 109 | * 512 bytes for SD cards. 110 | * 111 | * @returns 512 bytes as the sector size for SD cards. 112 | */ 113 | size_t ctr_sd_interface_sector_size(void *io); 114 | 115 | /** @brief Returns whether the SD is inserted. 116 | * 117 | * @returns True if the SD card is detected, false otherwise. 118 | */ 119 | bool ctr_sd_interface_inserted(void); 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #endif//CTR_SD_INTERFACE_H_ 126 | 127 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_sdmmc_implementation.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include "ctr_sdmmc_implementation.h" 10 | #include "sdmmc/sdmmc.h" 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | static inline int ctr_sdmmc_implementation_read(void *buffer, size_t buffer_size, uint64_t position, size_t count, sdmmc_readsectors read) 18 | { 19 | int res = 0; 20 | if (count && buffer_size) 21 | { 22 | size_t total_readable = count < buffer_size ? count : buffer_size; 23 | 24 | uint8_t *dest = buffer; 25 | uint8_t buf[0x200u]; 26 | const size_t base_sector = position / 0x200u; 27 | 28 | size_t bytes_read = 0; 29 | size_t sectors_read = 0; 30 | 31 | //Section 1: read first sector to extract the right number of bytes from it 32 | const size_t start_location = position % 0x200u; 33 | res |= read(base_sector, 1, buf); 34 | if (res) return res; 35 | 36 | sectors_read++; 37 | 38 | size_t section_readable = 0x200u - start_location; 39 | if (section_readable > total_readable) 40 | { 41 | section_readable = total_readable; 42 | } 43 | 44 | memcpy(dest, &buf[start_location], section_readable); 45 | bytes_read += section_readable; 46 | 47 | //Section 2: read all sectors until the last one 48 | section_readable = (total_readable - bytes_read); 49 | size_t mid_sectors = section_readable / 0x200; 50 | 51 | if (mid_sectors) 52 | { 53 | res |= read(base_sector + sectors_read, mid_sectors, dest + bytes_read); 54 | if (res) return res; 55 | sectors_read += mid_sectors; 56 | bytes_read += mid_sectors * 0x200u; 57 | } 58 | 59 | //Section 3: read last sector to extract the right number of bytes from it 60 | section_readable = total_readable - bytes_read; 61 | if (!res && section_readable) 62 | { 63 | res |= read(base_sector + sectors_read, 1, buf); 64 | if (res) return res; 65 | memcpy(dest + bytes_read, buf, section_readable); 66 | } 67 | } 68 | return res; 69 | } 70 | 71 | static inline int ctr_sdmmc_implementation_write(const void *buffer, size_t buffer_size, uint64_t position, sdmmc_readsectors read, sdmmc_writesectors write) 72 | { 73 | int res = 0; 74 | if (buffer_size) 75 | { 76 | const uint8_t *source = buffer; 77 | uint8_t buf[0x200u]; 78 | const size_t base_sector = position / 0x200u; 79 | const size_t start_location = position % 0x200u; 80 | 81 | size_t bytes_written = 0; 82 | size_t sectors_written = 0; 83 | 84 | //Section 1: read first sector to write back after adding the data to the sector 85 | res |= read(base_sector, ++sectors_written, buf); 86 | if (res) return res; 87 | 88 | const size_t writeable = 0x200u - start_location; 89 | bytes_written += writeable < buffer_size ? writeable : buffer_size; 90 | 91 | memcpy(buf + start_location, source, bytes_written); 92 | res |= write(base_sector, sectors_written, buf); 93 | if (res) return res; 94 | 95 | const size_t mid_sectors = (buffer_size-bytes_written) / 0x200u; 96 | //Section 2: write all sectors until the last one 97 | if (mid_sectors) 98 | { 99 | res |= write(base_sector + sectors_written, mid_sectors, source + bytes_written); 100 | if (res) return res; 101 | sectors_written += mid_sectors; 102 | bytes_written += mid_sectors * 0x200u; 103 | } 104 | 105 | //Section 3: read last sector to write back after adding the last bytes from the buffer 106 | if (bytes_written != buffer_size) 107 | { 108 | res |= read(base_sector + sectors_written, 1, buf); 109 | if (res) return res; 110 | memcpy(buf, source + bytes_written, buffer_size - bytes_written); 111 | write(base_sector + sectors_written, 1, buf); 112 | } 113 | } 114 | return res; 115 | } 116 | 117 | static inline int ctr_sdmmc_implementation_read_sector(void *buffer, size_t buffer_size, size_t sector, size_t count, sdmmc_readsectors read) 118 | { 119 | int res = 0; 120 | size_t read_size = (buffer_size / 512) < count ? buffer_size / 512 : count; 121 | if (read_size) 122 | { 123 | //What if read_size == 0? 124 | res = read(sector, read_size, (uint8_t*) buffer); 125 | } 126 | return res; 127 | } 128 | 129 | static inline int ctr_sdmmc_implementation_write_sector(const void *buffer, size_t buffer_size, size_t sector, sdmmc_writesectors write) 130 | { 131 | size_t write_size = (buffer_size / 512); 132 | int res; 133 | if (write_size) 134 | { 135 | res = write(sector, write_size, (const uint8_t*)buffer); 136 | } 137 | else 138 | { 139 | res = 1; //FIXME standardize return 140 | } 141 | return res; 142 | } 143 | 144 | #ifdef __cplusplus 145 | } 146 | #endif 147 | 148 | 149 | -------------------------------------------------------------------------------- /include/ctr9/io/ctr_sdmmc_implementation.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_SDMMC_IMPLEMENTATION_H_ 12 | #define CTR_SDMMC_IMPLEMENTATION_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /** @brief Pointer to an sdmmc function for reading sectors. 19 | * 20 | * Pointer to sdmmc function for reading sectors. A sector is defined by sdmmc 21 | * to be 0x200 or 512 bytes. 22 | * 23 | * @param[in] sector_no Sector to read. 24 | * @param[in] numsectors The number of sectors to read. 25 | * @param[out] out Pointer to buffer to store read data. The buffer must be 26 | * able to hold the number of sectors requested. 27 | * 28 | * @returns 0 on success, anything else indicates a failure. 29 | */ 30 | typedef int (*sdmmc_readsectors)(uint32_t sector_no, uint32_t numsectors, uint8_t *out); 31 | 32 | /** @brief Pointer to an sdmmc function for writing sectors. 33 | * 34 | * Pointer to sdmmc function for writing sectors. A sector is defined by sdmmc 35 | * to be 0x200 or 512 bytes. 36 | * 37 | * @param[in] sector_no Sector to write. 38 | * @param[in] numsectors The number of sectors to write. 39 | * @param[out] in Pointer to buffer with data to write. The buffer must contain 40 | * the specified number of sectors to write to prevent a buffer overflow. 41 | * 42 | * @returns 0 on success, anything else indicates a failure. 43 | */ 44 | typedef int (*sdmmc_writesectors)(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); 45 | 46 | /** @brief General implementation for reading bytes using an sdmmc function. 47 | * 48 | * @param[out] buffer Pointer to the buffer. 49 | * @param[in] buffer_size The size of the buffer in bytes. 50 | * @param[in] position Position/address in the io interface to read from. 51 | * @param[in] count The number of bytes to read. 52 | * @param[in] read Pointer to sdmmc function to read sectors. 53 | * 54 | * @returns 0 upon success, anything else means an error. 55 | */ 56 | static inline int ctr_sdmmc_implementation_read(void *buffer, size_t buffer_size, uint64_t position, size_t count, sdmmc_readsectors read); 57 | 58 | /** @brief General implementation for writing bytes using sdmmc functions. 59 | * 60 | * @param[in] buffer Pointer to the buffer. 61 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 62 | * write. 63 | * @param[in] position Position/address in the io interface to write to. 64 | * @param[in] read Pointer to sdmmc function to read sectors. 65 | * @param[in] write Pointer to sdmmc function to write sectors. 66 | * 67 | * @returns 0 upon success, anything else means an error. 68 | */ 69 | static inline int ctr_sdmmc_implementation_write(const void *buffer, size_t buffer_size, uint64_t position, sdmmc_readsectors read, sdmmc_writesectors write); 70 | 71 | /** @brief General implementation for reading sectors using an sdmmc function. 72 | * 73 | * sdmmc defines a sector as 512 bytes. 74 | * 75 | * @param[out] buffer Pointer to the buffer. 76 | * @param[in] buffer_size The size of the buffer in bytes. 77 | * @param[in] sector Sector position in the io interface to read from. 78 | * @param[in] count The number of sectors to read. 79 | * @param[in] read Pointer to sdmmc function to read sectors. 80 | * 81 | * @returns 0 upon success, anything else means an error. 82 | */ 83 | static inline int ctr_sdmmc_implementation_read_sector(void *buffer, size_t buffer_size, size_t sector, size_t count, sdmmc_readsectors read); 84 | 85 | /** @brief General implementation for writing sectors using an sdmmc function. 86 | * 87 | * sdmmc defines a sector as 512 bytes. 88 | * 89 | * @param[in] buffer Pointer to the buffer. 90 | * @param[in] buffer_size The size of the buffer, and the number of bytes to 91 | * write. If the number is not a multiple of the sector size, this function 92 | * will only write all the full sectors it can, ignoring the end of the 93 | * buffer that doesn't fit a sector. 94 | * @param[in] sector Sector Position in the io interface to write to. 95 | * @param[in] write Pointer to sdmmc function to write sectors. 96 | * 97 | * @returns 0 upon success, anything else means an error. 98 | */ 99 | static inline int ctr_sdmmc_implementation_write_sector(const void *buffer, size_t buffer_size, size_t sector, sdmmc_writesectors write); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #include "ctr_sdmmc_implementation.c" 106 | 107 | #endif//CTR_SDMMC_IMPLEMENTATION_H_ 108 | 109 | -------------------------------------------------------------------------------- /include/ctr9/io/fatfs/ctr_fatfs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_FATFS_H_ 12 | #define CTR_FATFS_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** @brief Initializes the entire IO subsystem. 23 | * 24 | * This is a helper function that takes in pointers to all necessary io 25 | * interfaces to hook up to the fatfs layer, and initializes them and prepares 26 | * fatfs for usage. 27 | * 28 | * @param[in,out] nand_io NAND io interface to initialize. May be used 29 | * independetly after initialization so long as it is not being 30 | * simultaneously used by fatfs. 31 | * @param[in,out] ctr_io CTRNAND io crypto interface to initialize. May be used 32 | * independetly after initialization so long as it is not being 33 | * simultaneously used by fatfs. 34 | * @param[in,out] twl_io TWL io crypto interface to initialize. May be used 35 | * independetly after initialization so long as it is not being 36 | * simultaneously used by fatfs. 37 | * @param[in,out] sd_io SD card io interface to initialize. May be used 38 | * independetly after initialization so long as it is not being 39 | * simultaneously used by fatfs. 40 | * 41 | * @post All structures passed in are initialized and the fatfs subsystem has 42 | * been prepared for usage. 43 | * 44 | * @returns 0 on success, anything else on failure. 45 | */ 46 | int ctr_fatfs_initialize( 47 | ctr_nand_interface *nand_io, 48 | ctr_nand_crypto_interface *ctr_io, 49 | ctr_nand_crypto_interface *twl_io, 50 | ctr_sd_interface *sd_io); 51 | 52 | /** @brief Initializes the IO subsystem for the NAND internal disks. 53 | * 54 | * This is a helper function that takes in pointers to all necessary io 55 | * interfaces to hook up to the fatfs layer for the internal NAND "disks," 56 | * consisting of TWLN, TWLP, and CTRNAND. This function also prepares fatfs for 57 | * usage. 58 | * 59 | * @param[in,out] nand_io NAND io interface to initialize. May be used 60 | * independetly after initialization so long as it is not being 61 | * simultaneously used by fatfs. 62 | * @param[in,out] ctr_io CTRNAND io crypto interface to initialize. May be used 63 | * independetly after initialization so long as it is not being 64 | * simultaneously used by fatfs. 65 | * @param[in,out] twl_io TWL io crypto interface to initialize. May be used 66 | * independetly after initialization so long as it is not being 67 | * simultaneously used by fatfs. 68 | * 69 | * @post All structures passed in are initialized and the fatfs subsystem has 70 | * been prepared for usage. 71 | * 72 | * @returns 0 on success, anything else on failure. 73 | */ 74 | int ctr_fatfs_internal_initialize( 75 | ctr_nand_interface *nand_io, 76 | ctr_nand_crypto_interface *ctr_io, 77 | ctr_nand_crypto_interface *twl_io); 78 | 79 | /** @brief Initializes the IO subsystem for the SD card. 80 | * 81 | * This is a helper function that takes in pointers to all necessary io 82 | * interfaces to hook up to the fatfs layer for the SD card. 83 | * 84 | * @param[in,out] sd_io SD card io interface to initialize. May be used 85 | * independetly after initialization so long as it is not being 86 | * simultaneously used by fatfs. 87 | * 88 | * @post All structures passed in are initialized and the fatfs subsystem has 89 | * been prepared for usage. 90 | * 91 | * @returns 0 on success, anything else on failure. Returns a failure if the SD 92 | * card was not inserted. 93 | */ 94 | int ctr_fatfs_sd_initialize(ctr_sd_interface *sd_io); 95 | 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | 102 | #endif//CTR_FATFS_H_ 103 | 104 | -------------------------------------------------------------------------------- /include/ctr9/io/fatfs/ctr_fatfs_disk.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #ifndef CTR_FATFS_DISK_H_ 12 | #define CTR_FATFS_DISK_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** @brief Structure holding information used by the fatfs implementation for 24 | * keeping track of which io interfaces are used for which partition 25 | * access. 26 | */ 27 | typedef struct 28 | { 29 | ctr_io_interface *io; //IO interface to use as disk 30 | size_t sector_offset; //Offset to the desired fatfs partition start 31 | size_t sectors; //Disk size in sectors 32 | DSTATUS status; //Status of disk 33 | 34 | } ctr_fatfs_disk; 35 | 36 | /** @brief Convenience function to initialize the fatfs system with the io 37 | * interfaces required to mount CTRNAND, TWLN, TWLP, and SD. 38 | * 39 | * @param[in,out] ctr_io A pointer to an initialized CTRNAND io layer. 40 | * @param[in,out] twl_io A pointer to an initialized TWL io layer. 41 | * @param[in,out] sd_io A pointer to an initialized SD io layer. 42 | * 43 | * @post The underlying structures in fatfs have been updated (using the custom 44 | * CTR_SETUP_DISK ioctl) to be able to mount CTRNAND, TWLN, TWLP, and SD. 45 | */ 46 | void ctr_fatfs_default_setup(ctr_nand_crypto_interface *ctr_io, ctr_nand_crypto_interface *twl_io, ctr_sd_interface *sd_io); 47 | 48 | /** @brief Initializes the ctr_fatfs_disk structure. 49 | * 50 | * @param[in] disk Pointer to structure to initialize. 51 | * @param[in,out] io Pointer to ctr_io_interface to use for the disk being 52 | * initialized. 53 | * @param[in] sector_offset Offset in sectors from the beginning of the given io 54 | * interface to use as the beginning of the fatfs drive (beginning of FAT 55 | * partition or MBR with FAT partition) 56 | * @param sectors Size in sectors of the FATFS disk/partition. 57 | */ 58 | void ctr_fatfs_disk_initialize(ctr_fatfs_disk *disk, void *io, size_t sector_offset, size_t sectors); 59 | 60 | /** @brief Destroys/clears the ctr_fatfs_disk structure. 61 | */ 62 | void ctr_fatfs_disk_destroy(ctr_fatfs_disk *disk); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif//CTR_FATFS_DISK_H_ 69 | 70 | -------------------------------------------------------------------------------- /include/ctr9/io/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "integer.h" 13 | #include 14 | 15 | /* Status of Disk Functions */ 16 | typedef BYTE DSTATUS; 17 | 18 | /* Results of Disk Functions */ 19 | typedef enum { 20 | RES_OK = 0, /* 0: Successful */ 21 | RES_ERROR, /* 1: R/W Error */ 22 | RES_WRPRT, /* 2: Write Protected */ 23 | RES_NOTRDY, /* 3: Not Ready */ 24 | RES_PARERR /* 4: Invalid Parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | DSTATUS disk_initialize_ (BYTE pdrv); 32 | DSTATUS disk_status_ (BYTE pdrv); 33 | DRESULT disk_read_ (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 34 | DRESULT disk_write_ (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 35 | DRESULT disk_ioctl_ (BYTE pdrv, BYTE cmd, void* buff); 36 | 37 | 38 | /* Disk Status Bits (DSTATUS) */ 39 | 40 | #define STA_NOINIT 0x01 /* Drive not initialized */ 41 | #define STA_NODISK 0x02 /* No medium in the drive */ 42 | #define STA_PROTECT 0x04 /* Write protected */ 43 | 44 | 45 | /* Command code for disk_ioctrl fucntion */ 46 | 47 | /* Generic command (Used by FatFs) */ 48 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 49 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 50 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 51 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 52 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 53 | 54 | /* Generic command (Not used by FatFs) */ 55 | #define CTRL_POWER 5 /* Get/Set power status */ 56 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 57 | #define CTRL_EJECT 7 /* Eject media */ 58 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 59 | 60 | /* MMC/SDC specific ioctl command */ 61 | #define MMC_GET_TYPE 10 /* Get card type */ 62 | #define MMC_GET_CSD 11 /* Get CSD */ 63 | #define MMC_GET_CID 12 /* Get CID */ 64 | #define MMC_GET_OCR 13 /* Get OCR */ 65 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 66 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 67 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 68 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 69 | 70 | /* ATA/CF specific ioctl command */ 71 | #define ATA_GET_REV 20 /* Get F/W revision */ 72 | #define ATA_GET_MODEL 21 /* Get model name */ 73 | #define ATA_GET_SN 22 /* Get serial number */ 74 | 75 | /* Custom IOCTLs */ 76 | #define CTR_SETUP_DISK 23 //Set up fatfs disk with the io interface 77 | 78 | /** @brief Structure used for CTR_SETUP_DISK ioctl 79 | */ 80 | typedef struct 81 | { 82 | void *io; //io interface to load into fatfs 83 | size_t sector_offset; //offset in sectors from beginning of partition 84 | size_t sectors; //Size in sectors of partition 85 | } ctr_setup_disk_parameters; 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /include/ctr9/io/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _FF_INTEGER 6 | #define _FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for C89 compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/ctr9/sha.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #define REG_SHACNT ((volatile uint32_t*)0x1000A000) 10 | #define REG_SHABLKCNT ((volatile uint32_t*)0x1000A004) 11 | #define REG_SHAHASH ((volatile uint32_t*)0x1000A040) 12 | #define REG_SHAINFIFO ((volatile uint32_t*)0x1000A080) 13 | 14 | #define SHA_CNT_STATE 0x00000003u 15 | #define SHA_CNT_OUTPUT_ENDIAN 0x00000008u 16 | #define SHA_CNT_MODE 0x00000030u 17 | #define SHA_CNT_ENABLE 0x00010000u 18 | #define SHA_CNT_ACTIVE 0x00020000u 19 | 20 | #define SHA_HASH_READY 0x00000000u 21 | #define SHA_NORMAL_ROUND 0x00000001u 22 | #define SHA_FINAL_ROUND 0x00000002u 23 | 24 | #define SHA256_MODE 0 25 | #define SHA224_MODE 0x00000010u 26 | #define SHA1_MODE 0x00000020u 27 | 28 | void sha_init(uint32_t mode); 29 | void sha_update(const void* src, uint32_t size); 30 | void sha_get(void* res); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /libctr9.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: @PACKAGE_NAME@ 7 | Description: Baremetal ARM9 library for the Nintendo 3DS 8 | URL: https://github.com/gemarcano/@PACKAGE_NAME@ 9 | Version: @VERSION@ 10 | Requires.private: ctr_core 11 | Libs: -L$(libdir) -lctr9 -lfreetype2 -lctrelf 12 | Cflags: -I(includedir) 13 | 14 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | include $(top_srcdir)/common.mk 2 | 3 | noinst_LTLIBRARIES = libctr9_arm.la 4 | libctr9_arm_la_SOURCES = ctr_interrupt.c ctr_irq.c 5 | libctr9_arm_la_CFLAGS = $(ARM_ONLY) -marm 6 | 7 | lib_LTLIBRARIES = libctr9.la 8 | libctr9_la_CCASFLAGS = -I$(top_srcdir)/data 9 | libctr9_la_SOURCES = aes.c ctr_nand_crypto_interface.c ctr_sd_interface.c sha.c \ 10 | ctr_io_interface.c ctr_nand_interface.c sdmmc/delay.s sdmmc/sdmmc.c i2c.c \ 11 | ctr_rtc.c fatfs/diskio.c fatfs/ff.c fatfs/option/unicode.c ctr_system.c \ 12 | fatfs/ctr_fatfs_disk.c ctr_disks.c ctr_fatfs.c \ 13 | ctr_interrupt_asm.s ctr_screen.c ctr_hid.c ctr_pxi.c gamecart/command_ctr.c \ 14 | gamecart/command_ntr.c gamecart/protocol.c gamecart/protocol_ctr.c \ 15 | gamecart/protocol_ntr.c ctr_cart_interface.c gamecart/delay.s ctr_headers.c \ 16 | ctr_timer.c ctr_system_clock.c ctr_cache.s \ 17 | ctr_crypto_interface.c ctr_memory_interface.c ctr_memory.c ctr_memory_asm.s \ 18 | ctr_aeskeydb.c ctr_firm.c ctr_drives.c ctr_console.c \ 19 | ctr_file_interface.c ctr_freetype.c crt0.s ctr_init.c ctr_circular_buffer.c\ 20 | ctr_elf_loader.c 21 | libctr9_la_LIBADD = libctr9_arm.la -lctr_core -lctrelf -lfreetype 22 | libctr9_la_LDFLAGS = $(AM_LDFLAGS) -static 23 | 24 | libctr9dir = $(pkgdatadir) 25 | libctr9_DATA=linker.ld 26 | 27 | EXTRA_libctr9_la_SOURCES = fatfs/option/cc932.c fatfs/option/cc936.c \ 28 | fatfs/option/cc949.c fatfs/option/cc950.c fatfs/option/ccsbcs.c \ 29 | fatfs/option/syscall.c fatfs/option/unicode.c 30 | 31 | includedirectory = $(top_srcdir)/include 32 | 33 | ctrincludedir = $(includedir)/ctr9 34 | ctrioincludedir = $(includedir)/ctr9/io 35 | ctrgamecartincludedir = $(includedir)/ctr9/gamecart 36 | ctrfatfsincludedir = $(includedir)/ctr9/io/fatfs 37 | ctrsdmmcincludedir = $(includedir)/ctr9/io/sdmmc 38 | 39 | #do not install fatfs headers 40 | noinst_HEADERS = $(includedirectory)/ctr9/io/fatfs/ff.h \ 41 | $(includedirectory)/ctr9/io/fatfs/ctr_fatfs_disk.h \ 42 | $(includedirectory)/ctr9/io/fatfs/diskio.h \ 43 | $(includedirectory)/ctr9/io/fatfs/ffconf.h \ 44 | $(includedirectory)/ctr9/io/fatfs/ctr_fatfs.h \ 45 | $(includedirectory)/ctr9/io/fatfs/integer.h 46 | 47 | ctrinclude_HEADERS = $(includedirectory)/ctr9/aes.h \ 48 | $(includedirectory)/ctr9/ctr_rtc.h $(includedirectory)/ctr9/ctr_system.h \ 49 | $(includedirectory)/ctr9/i2c.h $(includedirectory)/ctr9/io.h \ 50 | $(includedirectory)/ctr9/sha.h $(includedirectory)/ctr9/ctr_interrupt.h \ 51 | $(includedirectory)/ctr9/ctr_screen.h \ 52 | $(includedirectory)/ctr9/ctr_hid.h \ 53 | $(includedirectory)/ctr9/ctr_pxi.h \ 54 | $(includedirectory)/ctr9/ctr_headers.h \ 55 | $(includedirectory)/ctr9/ctr_timer.h \ 56 | $(includedirectory)/ctr9/ctr_irq.h \ 57 | $(includedirectory)/ctr9/ctr_system_clock.h \ 58 | $(includedirectory)/ctr9/ctr_cache.h \ 59 | $(includedirectory)/ctr9/ctr_memory.h \ 60 | $(includedirectory)/ctr9/ctr_aeskeydb.h \ 61 | $(includedirectory)/ctr9/ctr_firm.h \ 62 | $(includedirectory)/ctr9/ctr_freetype.h \ 63 | $(includedirectory)/ctr9/ctr_circular_buffer.h \ 64 | $(includedirectory)/ctr9/ctr_elf_loader.h 65 | 66 | ctrgamecartinclude_HEADERS = $(includedirectory)/ctr9/gamecart/protocol.h \ 67 | $(includedirectory)/ctr9/gamecart/command_ctr.h \ 68 | $(includedirectory)/ctr9/gamecart/command_ntr.h \ 69 | $(includedirectory)/ctr9/gamecart/protocol_ctr.h \ 70 | $(includedirectory)/ctr9/gamecart/protocol_ntr.h 71 | 72 | ctrioinclude_HEADERS = \ 73 | $(includedirectory)/ctr9/io/ctr_io_interface.h \ 74 | $(includedirectory)/ctr9/io/ctr_nand_crypto_interface.h \ 75 | $(includedirectory)/ctr9/io/ctr_nand_interface.h \ 76 | $(includedirectory)/ctr9/io/ctr_sd_interface.h \ 77 | $(includedirectory)/ctr9/io/ctr_sdmmc_implementation.h \ 78 | $(includedirectory)/ctr9/io/ctr_sdmmc_implementation.c \ 79 | $(includedirectory)/ctr9/io/ctr_disks.h \ 80 | $(includedirectory)/ctr9/io/ctr_cart_interface.h \ 81 | $(includedirectory)/ctr9/io/ctr_io_implementation.h \ 82 | $(includedirectory)/ctr9/io/ctr_io_implementation.c \ 83 | $(includedirectory)/ctr9/io/ctr_crypto_interface.h \ 84 | $(includedirectory)/ctr9/io/ctr_memory_interface.h \ 85 | $(includedirectory)/ctr9/io/ctr_drives.h \ 86 | $(includedirectory)/ctr9/io/ctr_console.h \ 87 | $(includedirectory)/ctr9/io/ctr_file_interface.h 88 | 89 | ctrsdmmcinclude_HEADERS = $(includedirectory)/ctr9/io/sdmmc/sdmmc.h 90 | 91 | -------------------------------------------------------------------------------- /src/ctr_aeskeydb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define LOAD_MEMBER(M,P) \ 7 | memcpy(&(M), P, sizeof(M)); \ 8 | P += sizeof(M) 9 | 10 | void ctr_aesdb_entry_load(ctr_aesdb_entry *entry, const void *data) 11 | { 12 | const uint8_t *entry_memory = (const uint8_t*)data; 13 | 14 | LOAD_MEMBER(entry->slot, entry_memory); 15 | LOAD_MEMBER(entry->type, entry_memory); 16 | LOAD_MEMBER(entry->id, entry_memory); 17 | LOAD_MEMBER(entry->reserved, entry_memory); 18 | LOAD_MEMBER(entry->is_devkit_key, entry_memory); 19 | LOAD_MEMBER(entry->is_encrypted, entry_memory); 20 | LOAD_MEMBER(entry->key, entry_memory); 21 | } 22 | 23 | void ctr_aesdb_entry_crypt_key(ctr_aesdb_entry *entry) 24 | { 25 | use_aeskey(0x2c); 26 | alignas(4) uint8_t ctr[16] = {0}; 27 | setup_aeskeyY(0x2c, ctr); 28 | ctr[0] = entry->slot; 29 | ctr[1] = entry->type; 30 | memcpy(ctr+2, entry->id, 10); 31 | set_ctr(ctr); 32 | ctr_decrypt(entry->key, entry->key, 1, AES_CNT_CTRNAND_MODE, ctr); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/ctr_cache.s: -------------------------------------------------------------------------------- 1 | @******************************************************************************* 2 | @* Copyright (C) 2016 Gabriel Marcano 3 | @* 4 | @* Refer to the COPYING.txt file at the top of the project directory. If that is 5 | @* missing, this file is licensed under the GPL version 2.0 or later. 6 | @* 7 | @******************************************************************************/ 8 | 9 | .arm 10 | 11 | .align 4 12 | 13 | .global ctr_cache_clean_and_flush_all, ctr_cache_flush_data_all 14 | .global ctr_cache_flush_data_entry, ctr_cache_data_clean_entry 15 | .global ctr_cache_data_clean_and_flush_entry, ctr_cache_data_clean_index_entry 16 | .global ctr_cache_data_clean_and_flush_index_entry 17 | .global ctr_cache_flush_instruction_all, ctr_cache_flush_instruction_entry 18 | .global ctr_cache_prefetch_instruction_line, ctr_cache_clean_and_flush 19 | .global ctr_cache_clean_data_range, ctr_cache_flush_data_range 20 | .global ctr_cache_flush_instruction_range, ctr_cache_drain_write_buffer 21 | 22 | .type ctr_cache_clean_and_flush_all, %function 23 | .type ctr_cache_flush_data_all, %function 24 | .type ctr_cache_flush_data_entry, %function 25 | .type ctr_cache_data_clean_entry, %function 26 | .type ctr_cache_data_clean_and_flush_entry, %function 27 | .type ctr_cache_data_clean_index_entry, %function 28 | .type ctr_cache_data_clean_and_flush_index_entry, %function 29 | .type ctr_cache_flush_instruction_all, %function 30 | .type ctr_cache_flush_instruction_entry, %function 31 | .type ctr_cache_prefetch_instruction_line, %function 32 | .type ctr_cache_clean_and_flush, %function 33 | .type ctr_cache_clean_data_range, %function 34 | .type ctr_cache_flush_data_range, %function 35 | .type ctr_cache_flush_instruction_range, %function 36 | .type ctr_cache_drain_write_buffer, %function 37 | 38 | ctr_cache_clean_and_flush_all: 39 | mov r1, #0 @segment 40 | 41 | 1: @outer_loop 42 | mov r0, #0 @line 43 | 2: @inner_loop 44 | orr r2, r1, r0 @make r2 be the resulting combination of 45 | @segment and line 46 | 47 | mcr p15, 0, r2, c7, c14, 2 @Clean and flush the line 48 | 49 | add r0, r0, #0x20 @move line to next line 50 | 51 | @The number of lines depends on the cache size, 0x400 for the 52 | @3DS data cache since it has 8KB of cache. Refer to the ARM 53 | @documentation for more details. 54 | cmp r0, #0x400 55 | bne 2b @inner_loop 56 | 57 | add r1, r1, #0x40000000 58 | cmp r1, #0x0 59 | bne 1b @outer_loop 60 | 61 | mov r0, #0 62 | mcr p15, 0, r0, c7, c5, 0 @Flush instruction cache 63 | mcr p15, 0, r0, c7, c10, 4 @drain write buffer 64 | bx lr 65 | 66 | ctr_cache_flush_data_all: 67 | mov r0, #0 68 | mcr p15, 0, r0, c7, c6, 0 69 | bx lr 70 | 71 | .macro define_entry_function c, segment=1 72 | bic r0, #0x1F 73 | mcr p15, 0, r0, c7, \c, \segment 74 | bx lr 75 | .endm 76 | 77 | ctr_cache_flush_data_entry: 78 | define_entry_function c6 79 | 80 | ctr_cache_data_clean_entry: 81 | define_entry_function c10 82 | 83 | ctr_cache_data_clean_and_flush_entry: 84 | define_entry_function c14 85 | 86 | ctr_cache_data_clean_index_entry: 87 | lsl r0, #30 88 | bic r1, #0xFFFFFFC0 89 | orr r0, r0, r1, lsl #5 90 | define_entry_function c10 2 91 | 92 | ctr_cache_data_clean_and_flush_index_entry: 93 | lsl r0, #30 94 | bic r1, #0xFFFFFFC0 95 | orr r0, r0, r1, lsl #5 96 | define_entry_function c14 2 97 | 98 | ctr_cache_flush_instruction_all: 99 | mov r0, #0 100 | mcr p15, 0, r0, c7, c5, 0 101 | bx lr 102 | 103 | ctr_cache_flush_instruction_entry: 104 | mcr p15, 0, r0, c7, c5, 1 105 | bx lr 106 | 107 | ctr_cache_prefetch_instruction_line: 108 | mcr p15, 0, r0, c7, c13, 1 109 | 110 | .macro define_range_function c 111 | cmp r0, r1 112 | bhs 2f 113 | 114 | 1: 115 | mcr p15, 0, r0, c7, \c, 1 116 | add r0, #32 117 | cmp r0, r1 118 | ble 1b 119 | 120 | 2: 121 | bx lr 122 | .endm 123 | 124 | ctr_cache_clean_and_flush_data_range: 125 | define_range_function c14 126 | 127 | ctr_cache_clean_data_range: 128 | define_range_function c10 129 | 130 | ctr_cache_flush_data_range: 131 | define_range_function c6 132 | 133 | ctr_cache_flush_instruction_range: 134 | define_range_function c5 135 | 136 | ctr_cache_drain_write_buffer: 137 | mov r0, #0 138 | mcr p15, 0, r0, c7, c10, 4 139 | bx lr 140 | -------------------------------------------------------------------------------- /src/ctr_circular_buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | void ctr_circular_buffer_initialize(ctr_circular_buffer *buffer, size_t size) 8 | { 9 | ctr_core_circular_buffer_initialize(buffer, size); 10 | } 11 | 12 | bool ctr_circular_buffer_push_back(ctr_circular_buffer *buffer, char data) 13 | { 14 | return ctr_core_circular_buffer_push_back(buffer, data); 15 | } 16 | 17 | bool ctr_circular_buffer_pop_front(ctr_circular_buffer *buffer, char *data) 18 | { 19 | return ctr_core_circular_buffer_pop_front(buffer, data);; 20 | } 21 | 22 | bool ctr_circular_buffer_get(ctr_circular_buffer *buffer, size_t index, char *data) 23 | { 24 | return ctr_core_circular_buffer_get(buffer, index, data); 25 | } 26 | 27 | size_t ctr_circular_buffer_size(ctr_circular_buffer *buffer) 28 | { 29 | return ctr_core_circular_buffer_size(buffer); 30 | } 31 | 32 | size_t ctr_circular_buffer_count(ctr_circular_buffer *buffer) 33 | { 34 | return ctr_core_circular_buffer_count(buffer); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/ctr_console.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //FIXME Freetype interactions are wonky. I'm not handling the cases where metrics can be negative due to changes in text orientation 14 | 15 | #include 16 | 17 | int ctr_console_initialize(const ctr_screen *screen) 18 | { 19 | return ctr_core_console_initialize(screen); 20 | } 21 | 22 | short ctr_console_get_char_width(char c) 23 | { 24 | return ctr_core_console_get_char_width(c); 25 | } 26 | 27 | unsigned int ctr_console_get_char_height(void) 28 | { 29 | return ctr_core_console_get_char_height(); 30 | } 31 | 32 | void ctr_console_draw(char c) 33 | { 34 | ctr_core_console_draw(c); 35 | } 36 | 37 | void ctr_console_clear(void) 38 | { 39 | ctr_core_console_clear(); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/ctr_disks.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int ctr_disks_initialize( 18 | ctr_nand_interface *nand_io, 19 | ctr_nand_crypto_interface *ctr_io, 20 | ctr_nand_crypto_interface *twl_io, 21 | ctr_sd_interface *sd_io) 22 | { 23 | int result = 0; 24 | if (nand_io) 25 | { 26 | result |= ctr_nand_interface_initialize(nand_io); 27 | if (!result) 28 | { 29 | if (ctr_io) 30 | { 31 | uint8_t encryption_type = 0; 32 | result |= ctr_io_read(nand_io, &encryption_type, sizeof(encryption_type), 0x118 + 0x4, sizeof(encryption_type)); 33 | uint8_t keyslot; 34 | switch (encryption_type) 35 | { 36 | default: //default to the o3DS keyslot FIXME is this a good default behavior? 37 | case 0x02: 38 | keyslot = 0x04; 39 | break; 40 | case 0x03: 41 | keyslot = 0x05; 42 | break; 43 | } 44 | result |= ctr_nand_crypto_interface_initialize(ctr_io, keyslot, NAND_CTR, (ctr_io_interface*)nand_io); 45 | } 46 | 47 | if (twl_io) 48 | { 49 | result |= ctr_nand_crypto_interface_initialize(twl_io, 0x03, NAND_TWL, (ctr_io_interface*)nand_io); 50 | } 51 | } 52 | } 53 | else if (ctr_io || twl_io) 54 | { 55 | result |= -1; 56 | } 57 | 58 | if (sd_io) 59 | { 60 | result |= ctr_sd_interface_initialize(sd_io); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/ctr_elf_loader.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | void ctr_load_header(Elf32_Ehdr *header, FILE *file) 16 | { 17 | fseek(file, 0, SEEK_SET); 18 | char buffer[sizeof(*header)]; 19 | fread(buffer, sizeof(buffer), 1, file); 20 | elf_load_header(header, buffer); 21 | } 22 | 23 | static int set_position(FILE *file, uint64_t position) 24 | { 25 | if (fseek(file, 0, SEEK_SET)) return -1; 26 | while (position > INT_MAX) 27 | { 28 | int pos = INT_MAX; 29 | if (fseek(file, pos, SEEK_CUR)) return -1; 30 | position -= INT_MAX; 31 | } 32 | 33 | if (fseek(file, (int)position, SEEK_CUR)) return -1; 34 | return 0; 35 | } 36 | 37 | int ctr_load_segment(const Elf32_Phdr *header, FILE *file) 38 | { 39 | size_t program_size = header->p_filesz; 40 | size_t mem_size = header->p_memsz; 41 | void *location = (void*)(header->p_vaddr); 42 | 43 | size_t type = header->p_type; 44 | 45 | switch (type) 46 | { 47 | case PT_LOAD: 48 | break; 49 | case PT_ARM_EXIDX: 50 | return 0; //Ignore this segment 51 | default: 52 | return 1; 53 | } 54 | 55 | set_position(file, header->p_offset); 56 | fread(location, program_size, 1, file); 57 | memset(program_size + (char*)location, 0, mem_size - program_size); 58 | 59 | ctr_cache_clean_data_range(location, (char*)location + mem_size); 60 | ctr_cache_flush_instruction_range(location, (char*)location + mem_size); 61 | ctr_cache_drain_write_buffer(); 62 | 63 | return 0; 64 | } 65 | 66 | int ctr_load_segments(const Elf32_Ehdr *header, FILE *file) 67 | { 68 | int res = 0; 69 | size_t pnum = header->e_phnum; 70 | char buffer[pnum][header->e_phentsize]; 71 | 72 | set_position(file, header->e_phoff); 73 | res = 1 != fread(buffer, sizeof(buffer), 1, file); 74 | 75 | if (res) 76 | return res; 77 | 78 | for (size_t i = 0; i < pnum; ++i) 79 | { 80 | Elf32_Phdr pheader; 81 | elf_load_program_header(&pheader, buffer[i]); 82 | res = ctr_load_segment(&pheader, file); 83 | if (res) 84 | return res; 85 | } 86 | 87 | return res; 88 | } 89 | 90 | bool ctr_check_elf(Elf32_Ehdr *header) 91 | { 92 | if (!(header->e_ident[EI_MAG0] == (char)0x7f && 93 | header->e_ident[EI_MAG1] == 'E' && 94 | header->e_ident[EI_MAG2] == 'L' && 95 | header->e_ident[EI_MAG3] == 'F')) 96 | return false; 97 | 98 | if (header->e_ident[EI_CLASS] != 1) 99 | return false; 100 | 101 | if (header->e_ident[EI_DATA] != 1) 102 | return false; 103 | 104 | if (header->e_ident[EI_VERSION] != EV_CURRENT) 105 | return false; 106 | 107 | if (header->e_type != ET_EXEC) 108 | return false; 109 | 110 | if (header->e_machine != EM_ARM) 111 | return false; 112 | 113 | if (header->e_version != EV_CURRENT) 114 | return false; 115 | 116 | if (header->e_entry == 0) 117 | return false; 118 | 119 | if (header->e_phoff == 0) 120 | return false; 121 | 122 | if (header->e_ehsize == 0) 123 | return false; 124 | 125 | return true; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /src/ctr_fatfs.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | /** @file */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int ctr_fatfs_initialize( 19 | ctr_nand_interface *nand_io, 20 | ctr_nand_crypto_interface *ctr_io, 21 | ctr_nand_crypto_interface *twl_io, 22 | ctr_sd_interface *sd_io) 23 | { 24 | int result = ctr_disks_initialize(nand_io, ctr_io, twl_io, sd_io); 25 | ctr_fatfs_default_setup(ctr_io, twl_io, sd_io); 26 | return result; 27 | } 28 | 29 | int ctr_fatfs_internal_initialize( 30 | ctr_nand_interface *nand_io, 31 | ctr_nand_crypto_interface *ctr_io, 32 | ctr_nand_crypto_interface *twl_io) 33 | { 34 | int result = ctr_disks_initialize(nand_io, ctr_io, twl_io, NULL); 35 | ctr_fatfs_default_setup(ctr_io, twl_io, NULL); 36 | return result; 37 | } 38 | 39 | int ctr_fatfs_sd_initialize(ctr_sd_interface *sd_io) 40 | { 41 | int result = ctr_disks_initialize(NULL, NULL, NULL, sd_io); 42 | ctr_fatfs_default_setup(NULL, NULL, sd_io); 43 | return result; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/ctr_file_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | //FIXME these are unique per instance... or are they? 18 | 19 | static const ctr_io_interface file_base = 20 | { 21 | ctr_file_interface_read, 22 | ctr_file_interface_write, 23 | ctr_file_interface_read_sector, 24 | ctr_file_interface_write_sector, 25 | ctr_file_interface_disk_size, 26 | ctr_file_interface_sector_size 27 | }; 28 | 29 | int ctr_file_interface_initialize(ctr_file_interface *io, FILE *file) 30 | { 31 | io->base = file_base; 32 | io->file = file; 33 | struct stat st; 34 | fstat(fileno(file), &st); 35 | return st.st_size < 512; //FIXME is this good enough? 36 | } 37 | 38 | void ctr_file_interface_destroy(ctr_file_interface *io) 39 | { 40 | *io = (ctr_file_interface){0}; 41 | } 42 | 43 | static int set_position(FILE *file, uint64_t position) 44 | { 45 | if (fseek(file, 0, SEEK_SET)) return -1; 46 | while (position > INT_MAX) 47 | { 48 | int pos = INT_MAX; 49 | if (fseek(file, pos, SEEK_CUR)) return -1; 50 | position -= INT_MAX; 51 | } 52 | 53 | if (fseek(file, (int)position, SEEK_CUR)) return -1; 54 | return 0; 55 | } 56 | 57 | int ctr_file_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 58 | { 59 | int result = 0; 60 | if (count) 61 | { 62 | ctr_file_interface *file_io = io; 63 | size_t readable = count < buffer_size ? count : buffer_size; 64 | result = set_position(file_io->file, position); 65 | if (result == 0) 66 | { 67 | size_t amount_read = fread(buffer, readable, 1, file_io->file); 68 | if (amount_read != 1) 69 | result = -1; //FIXME is this what I want if we read less than we could? 70 | } 71 | } 72 | 73 | return result; 74 | } 75 | 76 | int ctr_file_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 77 | { 78 | int result = 0; 79 | if (buffer_size) 80 | { 81 | ctr_file_interface *file_io = io; 82 | result = set_position(file_io->file, position); 83 | 84 | if (result == 0) 85 | { 86 | size_t amount_written = fwrite(buffer, buffer_size, 1, file_io->file); 87 | if (amount_written != 1) 88 | { 89 | result = -1; //FIXME, is this what I want if we write less than we could? 90 | } 91 | } 92 | } 93 | 94 | return result; 95 | } 96 | 97 | int ctr_file_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 98 | { 99 | int result = 0; 100 | if (count) 101 | { 102 | ctr_file_interface *file_io = io; 103 | size_t readable = count < buffer_size/512 ? count : buffer_size/512; 104 | result = set_position(file_io->file, sector * 512); 105 | if (result == 0) 106 | { 107 | size_t rb = fread(buffer, readable * 512, 1, file_io->file); 108 | if (rb != 1) 109 | result = -1; //FIXME see others 110 | } 111 | } 112 | 113 | return result; 114 | } 115 | 116 | int ctr_file_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 117 | { 118 | int result = 0; 119 | if (buffer_size/512) 120 | { 121 | ctr_file_interface *file_io = io; 122 | result = set_position(file_io->file, sector * 512); 123 | 124 | if (result == 0) 125 | { 126 | size_t writeable = buffer_size - buffer_size % 512; 127 | size_t wb = fwrite(buffer, writeable, 1, file_io->file); 128 | if (wb != 1) 129 | result = -1; //FIXME see others 130 | } 131 | } 132 | 133 | return result != 0; 134 | } 135 | 136 | uint64_t ctr_file_interface_disk_size(void *io) 137 | { 138 | ctr_file_interface *file_io = io; 139 | struct stat st; 140 | fstat(fileno(file_io->file), &st); 141 | 142 | //I DO want to explicitly change the sign of the result, a negative size 143 | //makes no sense, so I will use the negative bit as part of the unsigned 144 | //number, &st); 145 | return (size_t)(st.st_size); 146 | } 147 | 148 | size_t ctr_file_interface_sector_size(void *io) 149 | { 150 | return 512; //FIXME this isn't right always... is there a way to query fatfs about it? 151 | } 152 | 153 | -------------------------------------------------------------------------------- /src/ctr_firm.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void ctr_firm_section_header_load(ctr_firm_section_header *header, const void *data) 4 | { 5 | ctr_core_firm_section_header_load(header, data); 6 | } 7 | 8 | void ctr_firm_header_load(ctr_firm_header *header, const void *data) 9 | { 10 | ctr_core_firm_header_load(header, data); 11 | } 12 | 13 | void ctr_arm9bin_header_load(ctr_arm9bin_header *header, const void *data) 14 | { 15 | ctr_core_arm9bin_header_load(header, data); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/ctr_freetype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include FT_FREETYPE_H 6 | #include FT_CACHE_H 7 | 8 | #include 9 | 10 | int ctr_freetype_initialize(void) 11 | { 12 | return ctr_core_freetype_initialize(); 13 | } 14 | 15 | FTC_SBit ctr_freetype_prepare_character(char c) 16 | { 17 | return ctr_core_freetype_prepare_character(c); 18 | } 19 | 20 | void ctr_freetype_draw(ctr_screen *screen, size_t x, size_t y, char c, uint32_t pixel, uint32_t bg) 21 | { 22 | ctr_core_freetype_draw(screen, x, y, c, pixel, bg); 23 | } 24 | 25 | 26 | FT_Face ctr_freetype_get_face(void) 27 | { 28 | return ctr_core_freetype_get_face(); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/ctr_headers.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void ctr_ncsd_header_load(ctr_ncsd_cart_header *header, const uint8_t *data, size_t data_size) 8 | { 9 | ctr_core_ncsd_header_load(header, data, data_size); 10 | } 11 | 12 | void ctr_ncch_header_load(ctr_ncch_header *header, const uint8_t *data, size_t data_size) 13 | { 14 | ctr_core_ncch_header_load(header, data, data_size); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/ctr_hid.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | 12 | bool ctr_hid_button_status(ctr_hid_button_type buttons) 13 | { 14 | return ctr_core_hid_button_status(buttons); 15 | } 16 | 17 | ctr_hid_button_type ctr_hid_get_buttons(void) 18 | { 19 | return ctr_core_hid_get_buttons(); 20 | } 21 | 22 | //This was taken and adapted from b1l1s's hid.c 23 | void ctr_input_wait(void) 24 | { 25 | ctr_core_input_wait(); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/ctr_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct draw_s 8 | { 9 | void* top_left; 10 | void* top_right; 11 | void* sub; 12 | } draw_s; 13 | 14 | void __attribute__((weak)) ctr_libctr9_init(void); 15 | 16 | void __attribute__((weak)) ctr_libctr9_init(void) 17 | { 18 | ctr_pxi_initialize(); 19 | draw_s *cakehax_fbs = (draw_s*)0x23FFFE00; 20 | ctr_screen_initialize(&ctr_screen_top, cakehax_fbs->top_left, 400, 240, CTR_GFX_PIXEL_RGB8); 21 | ctr_screen_initialize(&ctr_screen_bottom, cakehax_fbs->sub, 320, 240, CTR_GFX_PIXEL_RGB8); 22 | ctr_console_initialize(&ctr_screen_bottom); 23 | 24 | ctr_freetype_initialize(); 25 | ctr_drives_initialize(); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/ctr_interrupt.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void ctr_interrupt_reset_veneer(void); 15 | void ctr_interrupt_undef_veneer(void); 16 | void ctr_interrupt_swi_veneer(void); 17 | void ctr_interrupt_preabrt_veneer(void); 18 | void ctr_interrupt_databrt_veneer(void); 19 | void ctr_interrupt_irq_veneer(void); 20 | void ctr_interrupt_fiq_veneer(void); 21 | 22 | typedef void (*interrupt_function)(void); 23 | typedef void (*ctr_interrupt_handler)(uint32_t *register_array, void *data); 24 | 25 | ctr_interrupt_handler ctr_interrupt_handlers[7] = {0}; 26 | void *ctr_interrupt_data[7] = {0}; 27 | 28 | #define ACCESS_FUNCTION_PTR(x) (*((interrupt_function*)(x))) 29 | 30 | void ctr_interrupt_set(ctr_interrupt_enum interrupt_type, ctr_interrupt_handler handler, void *data) 31 | { 32 | switch (interrupt_type) 33 | { 34 | case CTR_INTERRUPT_RESET: 35 | case CTR_INTERRUPT_UNDEF: 36 | case CTR_INTERRUPT_SWI: 37 | case CTR_INTERRUPT_PREABRT: 38 | case CTR_INTERRUPT_DATABRT: 39 | case CTR_INTERRUPT_IRQ: 40 | case CTR_INTERRUPT_FIQ: 41 | ctr_interrupt_handlers[interrupt_type] = handler; 42 | ctr_interrupt_data[interrupt_type] = data; 43 | break; 44 | 45 | default: 46 | break; //Set nothing 47 | } 48 | } 49 | 50 | __attribute__((noinline)) 51 | void ctr_interrupt_prepare(void) 52 | { 53 | //Secondary handler. Read payload address from next word 54 | ACCESS_FUNCTION_PTR(0x00008020) = (interrupt_function)0xE51FF004; 55 | ACCESS_FUNCTION_PTR(0x00008028) = (interrupt_function)0xE51FF004; 56 | ACCESS_FUNCTION_PTR(0x00008030) = (interrupt_function)0xE51FF004; 57 | ACCESS_FUNCTION_PTR(0x00008038) = (interrupt_function)0xE51FF004; 58 | ACCESS_FUNCTION_PTR(0x00008040) = (interrupt_function)0xE51FF004; 59 | ACCESS_FUNCTION_PTR(0x00008048) = (interrupt_function)0xE51FF004; 60 | ACCESS_FUNCTION_PTR(0x00008050) = (interrupt_function)0xE51FF004; 61 | 62 | //Pointers to veneers, which then would load the actual user provide 63 | //handlers 64 | ACCESS_FUNCTION_PTR(0x00008024) = ctr_interrupt_reset_veneer; 65 | ACCESS_FUNCTION_PTR(0x0000802C) = ctr_interrupt_undef_veneer; 66 | ACCESS_FUNCTION_PTR(0x00008034) = ctr_interrupt_swi_veneer; 67 | ACCESS_FUNCTION_PTR(0x0000803C) = ctr_interrupt_preabrt_veneer; 68 | ACCESS_FUNCTION_PTR(0x00008044) = ctr_interrupt_databrt_veneer; 69 | ACCESS_FUNCTION_PTR(0x0000804C) = ctr_interrupt_irq_veneer; 70 | ACCESS_FUNCTION_PTR(0x00008054) = ctr_interrupt_fiq_veneer; 71 | 72 | //Actual exception handling code. Jumps to the secondary handler. 73 | ACCESS_FUNCTION_PTR(0x00008000) = (interrupt_function)0xEA000006u; 74 | ACCESS_FUNCTION_PTR(0x00008004) = (interrupt_function)0xEA000007u; 75 | ACCESS_FUNCTION_PTR(0x00008008) = (interrupt_function)0xEA000008u; 76 | ACCESS_FUNCTION_PTR(0x0000800C) = (interrupt_function)0xEA000009u; 77 | ACCESS_FUNCTION_PTR(0x00008010) = (interrupt_function)0xEA00000Au; 78 | ACCESS_FUNCTION_PTR(0x00008014) = (interrupt_function)0xEAFFFFFEu; 79 | ACCESS_FUNCTION_PTR(0x00008018) = (interrupt_function)0xEA00000Au; 80 | ACCESS_FUNCTION_PTR(0x0000801C) = (interrupt_function)0xEA00000Bu; 81 | 82 | ctr_cache_clean_data_range((void*)0x8000, (void*)0x10000); 83 | ctr_cache_flush_instruction_range((void*)0x0, (void*)0x8000); 84 | ctr_cache_drain_write_buffer(); 85 | 86 | //switch to low vectors 87 | asm volatile ( 88 | "mrc p15, 0, r0, c1, c0, 0 \n\t" 89 | "bic r0, #(1<<13) \n\t" 90 | "mcr p15, 0, r0, c1, c0, 0 \n\t" 91 | :::"r0" 92 | ); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/ctr_interrupt_asm.s: -------------------------------------------------------------------------------- 1 | @******************************************************************************* 2 | @* Copyright (C) 2016 Gabriel Marcano 3 | @* 4 | @* Refer to the COPYING.txt file at the top of the project directory. If that is 5 | @* missing, this file is licensed under the GPL version 2.0 or later. 6 | @* 7 | @******************************************************************************/ 8 | 9 | .arm 10 | 11 | .align 4 12 | 13 | .global ctr_interrupt_reset_veneer, ctr_interrupt_undef_veneer 14 | .global ctr_interrupt_swi_veneer, ctr_interrupt_preabrt_veneer 15 | .global ctr_interrupt_databrt_veneer, ctr_interrupt_irq_veneer 16 | .global ctr_interrupt_fiq_veneer 17 | 18 | .type ctr_interrupt_reset_veneer, %function 19 | .type ctr_interrupt_undef_veneer, %function 20 | .type ctr_interrupt_swi_veneer, %function 21 | .type ctr_interrupt_preabrt_veneer, %function 22 | .type ctr_interrupt_databrt_veneer, %function 23 | .type ctr_interrupt_irq_veneer, %function 24 | .type ctr_interrupt_irq_veneer, %function 25 | .type ctr_interrupt_fiq_veneer, %function 26 | 27 | .extern ctr_interrupt_handlers, ctr_interrupt_data 28 | 29 | @FIXME this code is not generally position independent 30 | 31 | @I'm aware this choice of canary is not secure-- the idea behind this is to 32 | @prevent program execution from continuing in the case of an accidental 33 | @overflow 34 | exception_canary: 35 | .word exception_stack_end 36 | exception_stack_end: 37 | .skip 8192 * 4 38 | exception_stack: 39 | 40 | .macro CTR_INTERRUPT_VENEER table_offset=0 41 | @Exceptions stack. Currently we don't support nested exceptions 42 | ldr sp, =exception_stack 43 | push {r0-r12,r14} @push "normal" registers 44 | 45 | @switch to previous mode to get previous sp and lr, then switch back 46 | mrs r1, cpsr @interrupt mode 47 | mrs r0, spsr @previous mode 48 | orr r0, #0xC0 @make sure interrupts are disabled in mode to be switched to 49 | bic r0, #0x20 @make sure the status flag T matches ARM mode 50 | 51 | @if the previous mode is USER, we don't want to switch to user but to system, 52 | @since system is privileged and shares the same registers as user 53 | and r2, r0, #0x1F @extract the mode bits from r0 54 | cmp r2, #0x10 @check if it's user mode 55 | bne 1f 56 | orr r0, #0x1F @set the mode to system if user mode was detected 57 | 1: 58 | 59 | @change mode 60 | msr cpsr_c, r0 61 | mov r2, sp 62 | mov r3, lr 63 | @switch back 64 | msr cpsr_c, r1 65 | 66 | mrs r0, spsr 67 | 68 | @push "special" registers, placing them in the front of the array to be 69 | @passed 70 | push {r0, r2, r3, r14} 71 | 72 | adr r1, ctr_interrupt_handlers_location 73 | ldr r2, [r1] 74 | add r1, r1, r2 75 | ldr r2, [r1, #\table_offset] 76 | mov r0, sp 77 | 78 | adr r1, ctr_interrupt_data_location 79 | ldr r3, [r1] 80 | add r1, r3 81 | ldr r1, [r1, #\table_offset] 82 | 83 | @Parameters: r0 - pointer to array on stack: 84 | @ cpsr, sp, lr, return, r0-r12 85 | blx r2 86 | 87 | @determine if the simple canary was damaged 88 | ldr r0, =exception_canary 89 | ldr r0, [r0] 90 | ldr r1, =exception_stack_end 91 | cmp r0, r1 92 | 93 | beq 2f 94 | @Who knows what was overwritten, just forcibly hang. 95 | b . 96 | 2: 97 | 98 | @now determine the mode we were in previously 99 | @if Thumb, make sure LR is updated 100 | pop {r0, r3, r4, r14} 101 | tst r0, #0x20 102 | beq 3f 103 | orr r14, r14, #1 104 | 105 | 3: 106 | str r14, [sp, #0x34] 107 | ldmfd sp!, {r0-r12, pc}^ 108 | .endm 109 | 110 | 111 | ctr_interrupt_reset_veneer: 112 | CTR_INTERRUPT_VENEER 0 113 | 114 | ctr_interrupt_undef_veneer: 115 | CTR_INTERRUPT_VENEER 4 116 | 117 | ctr_interrupt_swi_veneer: 118 | CTR_INTERRUPT_VENEER 8 119 | 120 | ctr_interrupt_preabrt_veneer: 121 | CTR_INTERRUPT_VENEER 12 122 | 123 | ctr_interrupt_databrt_veneer: 124 | CTR_INTERRUPT_VENEER 16 125 | 126 | ctr_interrupt_irq_veneer: 127 | CTR_INTERRUPT_VENEER 20 128 | 129 | ctr_interrupt_fiq_veneer: 130 | CTR_INTERRUPT_VENEER 24 131 | 132 | ctr_interrupt_handlers_location: 133 | .word ctr_interrupt_handlers - . 134 | 135 | ctr_interrupt_data_location: 136 | .word ctr_interrupt_data - . 137 | 138 | -------------------------------------------------------------------------------- /src/ctr_io_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | 11 | int ctr_io_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 12 | { 13 | ctr_io_interface *base = io; 14 | return base->read(io, buffer, buffer_size, position, count); 15 | } 16 | 17 | int ctr_io_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 18 | { 19 | ctr_io_interface *base = io; 20 | return base->write(io, buffer, buffer_size, position); 21 | } 22 | 23 | int ctr_io_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 24 | { 25 | ctr_io_interface *base = io; 26 | return base->read_sector(io, buffer, buffer_size, sector, count); 27 | } 28 | 29 | int ctr_io_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 30 | { 31 | ctr_io_interface *base = io; 32 | return base->write_sector(io, buffer, buffer_size, sector); 33 | } 34 | 35 | uint64_t ctr_io_disk_size(void *io) 36 | { 37 | ctr_io_interface *base = io; 38 | return base->disk_size(io); 39 | } 40 | 41 | size_t ctr_io_sector_size(void *io) 42 | { 43 | ctr_io_interface *base = io; 44 | return base->sector_size(io); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/ctr_irq.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | __attribute__((noinline)) 16 | void ctr_irq_master_disable(void) 17 | { 18 | asm volatile( 19 | "mrs r0, cpsr \n\t" 20 | "orr r0, r0, #0x80 \n\t" //disable IRQ, bit 7, active low 21 | "msr cpsr_c, r0 \n\t" 22 | ::: "r0" 23 | ); 24 | } 25 | 26 | __attribute__((noinline)) 27 | void ctr_irq_master_enable(void) 28 | { 29 | asm volatile ( 30 | "mrs r0, cpsr \n\t" 31 | "bic r0, r0, #0x80 \n\t" //enable IRQ, bit 7, active low 32 | "msr cpsr_c, r0 \n\t" 33 | ::: "r0" 34 | ); 35 | 36 | } 37 | 38 | static uint32_t critical_count = 0; 39 | static uint32_t saved_status = 0; 40 | 41 | __attribute__((noinline)) 42 | void ctr_irq_critical_enter(void) 43 | { 44 | uint32_t status = 0; 45 | asm volatile( 46 | "mrs r0, cpsr \n\t" 47 | "mov %0, r0 \n\t" 48 | "orr r0, r0, #0x80 \n\t" //disable IRQ, bit 7, active low 49 | "msr cpsr_c, r0 \n\t" 50 | :"+r"(status) 51 | :: "r0" 52 | ); 53 | 54 | ctr_irq_master_disable(); 55 | if (!critical_count++) 56 | { 57 | saved_status = status; 58 | } 59 | } 60 | 61 | __attribute__((noinline)) 62 | void ctr_irq_critical_exit(void) 63 | { 64 | if (!--critical_count) 65 | { 66 | uint32_t status = saved_status & 0x80; 67 | saved_status = status; 68 | asm volatile( 69 | "mrs r0, cpsr \n\t" 70 | "bic r0, r0, #0x80 \n\t" //enable IRQ, bit 7, active low 71 | "add r0, r0, %0 \n\t" //Restore saved 72 | "msr cpsr_c, r0 \n\t" 73 | ::"r"(status) 74 | : "r0" 75 | ); 76 | } 77 | 78 | } 79 | 80 | typedef void (*ctr_interrupt_handler)(uint32_t *register_array, void *data); 81 | 82 | static void (*ctr_irq_handlers[29])(void*) = { NULL }; 83 | static void *ctr_irq_data[29] = { NULL }; 84 | 85 | static void ctr_irq_handler(uint32_t *register_array, void *data) 86 | { 87 | //Check IRQ_IF 88 | uint32_t pending = IRQ_IF_REG; 89 | for (size_t i = 0; i < 30; ++i) 90 | { 91 | if (pending & (1u << i) && ctr_irq_handlers[i]) 92 | { 93 | ctr_irq_handlers[i](ctr_irq_data[i]); 94 | } 95 | } 96 | register_array[3] -= 4; 97 | } 98 | 99 | void ctr_irq_initialize(void) 100 | { 101 | ctr_interrupt_set(CTR_INTERRUPT_IRQ, ctr_irq_handler, NULL); 102 | } 103 | 104 | void ctr_irq_register(ctr_irq_enum irq, void (*handler)(void*), void *data) 105 | { 106 | if (irq < 29u) 107 | { 108 | ctr_irq_handlers[irq] = handler; 109 | } 110 | } 111 | 112 | void ctr_irq_acknowledge(ctr_irq_enum irq) 113 | { 114 | if (irq < 29u) 115 | { 116 | IRQ_IF_REG = 1u << irq; 117 | } 118 | } 119 | 120 | void ctr_irq_enable(ctr_irq_enum irq) 121 | { 122 | if (irq < 29u) 123 | { 124 | IRQ_IE_REG |= 1u << irq; 125 | } 126 | } 127 | 128 | void ctr_irq_disable(ctr_irq_enum irq) 129 | { 130 | if (irq < 29u) 131 | { 132 | IRQ_IE_REG &= ~(1u << irq); 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/ctr_memory_asm.s: -------------------------------------------------------------------------------- 1 | @******************************************************************************* 2 | @* Copyright (C) 2016 Gabriel Marcano 3 | @* 4 | @* Refer to the COPYING.txt file at the top of the project directory. If that is 5 | @* missing, this file is licensed under the GPL version 2.0 or later. 6 | @* 7 | @******************************************************************************/ 8 | 9 | .arm 10 | .align 4 11 | 12 | .type ctr_memory_get_itcm_register_, %function 13 | .type ctr_memory_get_dtcm_register_, %function 14 | .type ctr_memory_set_itcm_register_, %function 15 | .type ctr_memory_set_dtcm_register_, %function 16 | .type ctr_memory_itcm_state_, %function 17 | .type ctr_memory_dtcm_state_, %function 18 | .type ctr_memory_enable_itcm_, %function 19 | .type ctr_memory_disable_itcm_, %function 20 | .type ctr_memory_enable_dtcm_, %function 21 | .type ctr_memory_disable_dtcm_, %function 22 | 23 | .global ctr_memory_get_itcm_register_, ctr_memory_get_dtcm_register_ 24 | .global ctr_memory_set_itcm_register_, ctr_memory_set_dtcm_register_ 25 | .global ctr_memory_itcm_state_, ctr_memory_dtcm_state_ 26 | .global ctr_memory_enable_itcm_, ctr_memory_disable_itcm_ 27 | .global ctr_memory_enable_dtcm_, ctr_memory_disable_dtcm_ 28 | 29 | ctr_memory_get_itcm_register_: 30 | mrc p15, 0, r0, c9, c1, 1 31 | bx lr 32 | 33 | ctr_memory_get_dtcm_register_: 34 | mrc p15, 0, r0, c9, c1, 0 35 | bx lr 36 | 37 | ctr_memory_set_itcm_register_: 38 | mcr p15, 0, r0, c9, c1, 1 39 | bx lr 40 | 41 | ctr_memory_set_dtcm_register_: 42 | mcr p15, 0, r0, c9, c1, 0 43 | bx lr 44 | 45 | ctr_memory_itcm_state_: 46 | mrc p15, 0, r0, c1, c0, 0 47 | and r0, #0x40000 48 | bx lr 49 | 50 | ctr_memory_dtcm_state_: 51 | mrc p15, 0, r0, c1, c0, 0 52 | and r0, #0x10000 53 | bx lr 54 | 55 | ctr_memory_enable_itcm_: 56 | mrc p15, 0, r0, c1, c0, 0 57 | orr r0, #0x40000 58 | mcr p15, 0, r0, c1, c0, 0 59 | bx lr 60 | 61 | ctr_memory_disable_itcm_: 62 | mrc p15, 0, r0, c1, c0, 0 63 | bic r0, #0x40000 64 | mcr p15, 0, r0, c1, c0, 0 65 | bx lr 66 | 67 | ctr_memory_enable_dtcm_: 68 | mrc p15, 0, r0, c1, c0, 0 69 | orr r0, #0x10000 70 | mcr p15, 0, r0, c1, c0, 0 71 | bx lr 72 | 73 | ctr_memory_disable_dtcm_: 74 | mrc p15, 0, r0, c1, c0, 0 75 | bic r0, #0x10000 76 | mcr p15, 0, r0, c1, c0, 0 77 | bx lr 78 | 79 | -------------------------------------------------------------------------------- /src/ctr_memory_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static const ctr_io_interface memory_base = 15 | { 16 | ctr_memory_interface_read, 17 | ctr_memory_interface_write, 18 | ctr_memory_interface_read_sector, 19 | ctr_memory_interface_write_sector, 20 | ctr_memory_interface_disk_size, 21 | ctr_memory_interface_sector_size 22 | }; 23 | 24 | void ctr_memory_interface_initialize(ctr_memory_interface *io, void *buffer, size_t buffer_size) 25 | { 26 | io->base = memory_base; 27 | io->buffer = buffer; 28 | io->buffer_size = buffer_size; 29 | } 30 | 31 | void ctr_memory_interface_destroy(ctr_memory_interface *io) 32 | { 33 | *io = (ctr_memory_interface){0}; 34 | } 35 | 36 | int ctr_memory_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 37 | { 38 | return ctr_io_implementation_read(io, buffer, buffer_size, position, count, ctr_memory_interface_read_sector); 39 | } 40 | 41 | int ctr_memory_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 42 | { 43 | return ctr_io_implementation_write(io, buffer, buffer_size, position, ctr_memory_interface_read_sector, ctr_memory_interface_write_sector); 44 | } 45 | 46 | int ctr_memory_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 47 | { 48 | ctr_memory_interface *mem_io = io; 49 | size_t size_to_read = buffer_size < mem_io->buffer_size ? buffer_size : mem_io->buffer_size; 50 | size_to_read = size_to_read < count ? size_to_read : count; 51 | memmove(buffer, (char*)mem_io->buffer + sector, size_to_read); 52 | return 0; 53 | } 54 | 55 | int ctr_memory_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 56 | { 57 | ctr_memory_interface *mem_io = io; 58 | size_t size_to_write = buffer_size < mem_io->buffer_size ? buffer_size : mem_io->buffer_size; 59 | memmove((char*)mem_io->buffer + sector, buffer, size_to_write); 60 | return 0; 61 | } 62 | 63 | uint64_t ctr_memory_interface_disk_size(void *io) 64 | { 65 | return ((ctr_memory_interface*)io)->buffer_size; 66 | } 67 | 68 | size_t ctr_memory_interface_sector_size(void *io) 69 | { 70 | return 1u; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/ctr_nand_crypto_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | //FIXME these are unique per instance... or are they? 20 | 21 | static const ctr_io_interface nand_crypto_base = 22 | { 23 | ctr_nand_crypto_interface_read, 24 | ctr_nand_crypto_interface_write, 25 | ctr_nand_crypto_interface_read_sector, 26 | ctr_nand_crypto_interface_write_sector, 27 | ctr_nand_crypto_interface_disk_size, 28 | ctr_nand_crypto_interface_sector_size 29 | }; 30 | 31 | static inline void process_aes_ctr_blocks(void *buffer, void *ctr, uint64_t blocks, uint32_t mode) 32 | { 33 | ctr_decrypt(buffer, buffer, blocks, mode, ctr); 34 | } 35 | 36 | static inline void check_and_do_n3ds_init() 37 | { 38 | static bool setup = false; 39 | if (!setup && ctr_detect_a9lh_entry() && ctr_get_system_type() == SYSTEM_N3DS) 40 | { 41 | ctr_n3ds_ctrnand_keyslot_setup(); 42 | } 43 | } 44 | 45 | static inline void check_and_do_twl_init() 46 | { 47 | static bool setup = false; 48 | if (!setup && ctr_detect_a9lh_entry()) 49 | { 50 | ctr_twl_keyslot_setup(); 51 | } 52 | } 53 | 54 | int ctr_nand_crypto_interface_initialize(ctr_nand_crypto_interface *crypto_io, uint8_t keySlot, ctr_nand_crypto_type crypto_type, ctr_io_interface *lower_io) 55 | { 56 | crypto_io->base = nand_crypto_base; 57 | 58 | //Get the nonces for CTRNAND and TWL decryption 59 | uint32_t mode; 60 | uint32_t NandCid[4]; 61 | alignas(4) uint8_t shasum[32]; 62 | 63 | sdmmc_get_cid(true, NandCid); 64 | uint32_t ctr[4]; 65 | 66 | switch (crypto_type) 67 | { 68 | case NAND_CTR: 69 | check_and_do_n3ds_init(); 70 | sha_init(SHA256_MODE); 71 | sha_update((uint8_t*)NandCid, 16); 72 | sha_get(shasum); 73 | memcpy(ctr, shasum, 16); 74 | mode = AES_CNT_CTRNAND_MODE; 75 | break; 76 | 77 | case NAND_TWL: 78 | check_and_do_twl_init(); 79 | sha_init(SHA1_MODE); 80 | sha_update((uint8_t*)NandCid, 16); 81 | sha_get(shasum); 82 | for(uint32_t i = 0; i < 16u; i++) // little endian and reversed order 83 | { 84 | ((uint8_t*)ctr)[i] = shasum[15-i]; 85 | } 86 | mode = AES_CNT_TWLNAND_MODE; 87 | break; 88 | 89 | default: 90 | return 1; //Unknown type 91 | } 92 | 93 | ctr_crypto_interface_initialize(&crypto_io->crypto_io, keySlot, mode, CTR_CRYPTO_ENCRYPTED, CRYPTO_CTR, (uint8_t*)ctr, lower_io); 94 | return 0; 95 | } 96 | 97 | void ctr_nand_crypto_interface_destroy(ctr_nand_crypto_interface *crypto_io) 98 | { 99 | ctr_crypto_interface_destroy(&crypto_io->crypto_io); 100 | *crypto_io = (ctr_nand_crypto_interface){0}; 101 | } 102 | 103 | int ctr_nand_crypto_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 104 | { 105 | return ctr_io_implementation_read(io, buffer, buffer_size, position, count, ctr_nand_crypto_interface_read_sector); 106 | } 107 | 108 | int ctr_nand_crypto_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 109 | { 110 | return ctr_io_implementation_write(io, buffer, buffer_size, position, ctr_nand_crypto_interface_read_sector, ctr_nand_crypto_interface_write_sector); 111 | } 112 | 113 | int ctr_nand_crypto_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 114 | { 115 | ctr_nand_crypto_interface *crypto_io = io; 116 | return ctr_crypto_interface_read_sector(&crypto_io->crypto_io, buffer, buffer_size, sector, count); 117 | } 118 | 119 | int ctr_nand_crypto_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 120 | { 121 | ctr_nand_crypto_interface *crypto_io = io; 122 | return ctr_crypto_interface_write_sector(&crypto_io->crypto_io, buffer, buffer_size, sector); 123 | } 124 | 125 | uint64_t ctr_nand_crypto_interface_disk_size(void *io) 126 | { 127 | ctr_nand_crypto_interface *crypto_io = io; 128 | return crypto_io->crypto_io.base.disk_size(&crypto_io->crypto_io); 129 | } 130 | 131 | size_t ctr_nand_crypto_interface_sector_size(void *io) 132 | { 133 | ctr_nand_crypto_interface *crypto_io = io; 134 | return crypto_io->crypto_io.base.sector_size(&crypto_io->crypto_io); 135 | } 136 | 137 | -------------------------------------------------------------------------------- /src/ctr_nand_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static const ctr_io_interface nand_base = 15 | { 16 | ctr_nand_interface_read, 17 | ctr_nand_interface_write, 18 | ctr_nand_interface_read_sector, 19 | ctr_nand_interface_write_sector, 20 | ctr_nand_interface_disk_size, 21 | ctr_nand_interface_sector_size 22 | }; 23 | 24 | int ctr_nand_interface_initialize(ctr_nand_interface *io) 25 | { 26 | io->base = nand_base; 27 | InitSD(); 28 | return Nand_Init(); 29 | } 30 | 31 | void ctr_nand_interface_destroy(ctr_nand_interface *io) 32 | { 33 | *io = (ctr_nand_interface){0}; 34 | } 35 | 36 | int ctr_nand_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 37 | { 38 | return ctr_sdmmc_implementation_read(buffer, buffer_size, position, count, sdmmc_nand_readsectors); 39 | } 40 | 41 | int ctr_nand_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 42 | { 43 | return ctr_sdmmc_implementation_write(buffer, buffer_size, position, sdmmc_nand_readsectors, sdmmc_nand_writesectors); 44 | } 45 | 46 | int ctr_nand_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 47 | { 48 | return ctr_sdmmc_implementation_read_sector(buffer, buffer_size, sector, count, sdmmc_nand_readsectors); 49 | } 50 | 51 | int ctr_nand_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 52 | { 53 | return ctr_sdmmc_implementation_write_sector(buffer, buffer_size, sector, sdmmc_nand_writesectors); 54 | } 55 | 56 | uint64_t ctr_nand_interface_disk_size(void *io) 57 | { 58 | return getMMCDevice(0)->total_size * (uint64_t)512u; 59 | } 60 | 61 | size_t ctr_nand_interface_sector_size(void *io) 62 | { 63 | return 512u; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/ctr_pxi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | void ctr_pxi_initialize(void) 7 | { 8 | ctr_core_pxi_change_base((volatile uint32_t*)0x10008000); 9 | } 10 | 11 | bool ctr_pxi_send_empty_status(void) 12 | { 13 | return ctr_core_pxi_send_empty_status(); 14 | } 15 | 16 | bool ctr_pxi_send_full_status(void) 17 | { 18 | return ctr_core_pxi_send_full_status(); 19 | } 20 | 21 | bool ctr_pxi_get_send_empty_irq() 22 | { 23 | return ctr_core_pxi_get_send_empty_irq(); 24 | } 25 | 26 | void ctr_pxi_set_send_empty_irq(bool aState) 27 | { 28 | ctr_core_pxi_set_send_empty_irq(aState); 29 | } 30 | 31 | void ctr_pxi_fifo_send_clear(void) 32 | { 33 | ctr_core_pxi_fifo_send_clear(); 34 | } 35 | 36 | bool ctr_pxi_receive_empty_status(void) 37 | { 38 | return ctr_core_pxi_receive_empty_status(); 39 | } 40 | 41 | bool ctr_pxi_receive_full_status(void) 42 | { 43 | return ctr_core_pxi_receive_full_status(); 44 | } 45 | 46 | bool ctr_pxi_get_receive_not_empty_irq(void) 47 | { 48 | return ctr_core_pxi_get_receive_not_empty_irq(); 49 | } 50 | 51 | void ctr_pxi_set_receive_not_empty_irq(bool aState) 52 | { 53 | ctr_core_pxi_set_receive_not_empty_irq(aState); 54 | } 55 | 56 | void ctr_pxi_set_enabled(bool aState) 57 | { 58 | ctr_core_pxi_set_enabled(aState); 59 | } 60 | 61 | bool ctr_pxi_get_enabled(void) 62 | { 63 | return ctr_core_pxi_get_enabled(); 64 | } 65 | 66 | void ctr_pxi_fifo_ack(void) 67 | { 68 | ctr_core_pxi_fifo_ack(); 69 | } 70 | 71 | bool ctr_pxi_get_error(void) 72 | { 73 | return ctr_core_pxi_get_error(); 74 | } 75 | 76 | bool ctr_pxi_push(uint32_t aData) 77 | { 78 | return ctr_core_pxi_push(aData); 79 | } 80 | 81 | bool ctr_pxi_pop(uint32_t *apData) 82 | { 83 | return ctr_core_pxi_pop(apData); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/ctr_rtc.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | typedef struct 16 | { 17 | time_t time; 18 | 19 | } ctr_rtc; 20 | 21 | static inline uint8_t bcd_to_number(uint8_t bcd) 22 | { 23 | return (bcd & 0xF) + (bcd >> 4) * 10; 24 | } 25 | 26 | static ctr_rtc rtc; 27 | 28 | void ctr_rtc_init(void) 29 | { 30 | rtc.time = 0; 31 | } 32 | 33 | ctr_rtc_data ctr_rtc_gettime(void) 34 | { 35 | ctr_rtc_data data; 36 | i2cReadRegisterBuffer(I2C_DEV_MCU, 0x30, (uint8_t*)&data, sizeof(data)); 37 | return data; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/ctr_screen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void ctr_screen_enable_backlight(ctr_screen_enum aScreens) 5 | { 6 | ctr_core_screen_enable_backlight(aScreens); 7 | } 8 | 9 | void ctr_screen_disable_backlight(ctr_screen_enum aScreens) 10 | { 11 | ctr_core_screen_disable_backlight(aScreens); 12 | } 13 | 14 | void ctr_screen_initialize(ctr_screen *screen, uint8_t *framebuffer, size_t width, size_t height, ctr_screen_pixel format) 15 | { 16 | ctr_core_screen_initialize(screen, framebuffer, width, height, format); 17 | } 18 | 19 | void ctr_screen_clear(ctr_screen *screen, uint32_t pixel) 20 | { 21 | ctr_core_screen_clear(screen, pixel); 22 | } 23 | 24 | uint32_t ctr_screen_get_pixel(ctr_screen *screen, size_t x, size_t y) 25 | { 26 | return ctr_core_screen_get_pixel(screen, x, y); 27 | } 28 | 29 | void ctr_screen_set_pixel(ctr_screen *screen, size_t x, size_t y, uint32_t pixel) 30 | { 31 | ctr_core_screen_set_pixel(screen, x, y, pixel); 32 | } 33 | 34 | void ctr_screen_draw_bitmap(ctr_screen *screen, size_t x, size_t y, uint32_t pixel, ctr_screen_bitmap *bitmap) 35 | { 36 | ctr_core_screen_draw_bitmap(screen, x, y, pixel, bitmap); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/ctr_sd_interface.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static const ctr_io_interface sd_base = 16 | { 17 | ctr_sd_interface_read, 18 | ctr_sd_interface_write, 19 | ctr_sd_interface_read_sector, 20 | ctr_sd_interface_write_sector, 21 | ctr_sd_interface_disk_size, 22 | ctr_sd_interface_sector_size 23 | }; 24 | 25 | int ctr_sd_interface_initialize(ctr_sd_interface *io) 26 | { 27 | io->base = sd_base; 28 | InitSD(); 29 | return SD_Init(); 30 | } 31 | 32 | void ctr_sd_interface_destroy(ctr_sd_interface *io) 33 | { 34 | *io = (ctr_sd_interface){0}; 35 | } 36 | 37 | int ctr_sd_interface_read(void *io, void *buffer, size_t buffer_size, uint64_t position, size_t count) 38 | { 39 | return ctr_sdmmc_implementation_read(buffer, buffer_size, position, count, sdmmc_sdcard_readsectors); 40 | } 41 | 42 | int ctr_sd_interface_write(void *io, const void *buffer, size_t buffer_size, uint64_t position) 43 | { 44 | return ctr_sdmmc_implementation_write(buffer, buffer_size, position, sdmmc_sdcard_readsectors, sdmmc_sdcard_writesectors); 45 | } 46 | 47 | int ctr_sd_interface_read_sector(void *io, void *buffer, size_t buffer_size, size_t sector, size_t count) 48 | { 49 | return ctr_sdmmc_implementation_read_sector(buffer, buffer_size, sector, count, sdmmc_sdcard_readsectors); 50 | } 51 | 52 | int ctr_sd_interface_write_sector(void *io, const void *buffer, size_t buffer_size, size_t sector) 53 | { 54 | return ctr_sdmmc_implementation_write_sector(buffer, buffer_size, sector, sdmmc_sdcard_writesectors); 55 | } 56 | 57 | uint64_t ctr_sd_interface_disk_size(void *io) 58 | { 59 | return getMMCDevice(1)->total_size * (uint64_t)512u; 60 | } 61 | 62 | size_t ctr_sd_interface_sector_size(void *io) 63 | { 64 | return 512u; 65 | } 66 | 67 | bool ctr_sd_interface_inserted(void) 68 | { 69 | return sdmmc_sd_inserted(); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/ctr_system_clock.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | static void ctr_system_clock_interrupt_handler(void *data); 16 | 17 | static unsigned int active_clocks = 0; 18 | 19 | static ctr_system_clock *clocks[4] = { NULL }; 20 | 21 | void ctr_system_clock_initialize(ctr_system_clock *clock, ctr_timer timer) 22 | { 23 | clock->count = 0; 24 | if (timer < 4u) 25 | { 26 | ctr_irq_disable(CTR_IRQ_TIMER_0 + timer); 27 | 28 | ctr_timer_disable(timer); 29 | ctr_timer_disable_irq(timer); 30 | ctr_irq_acknowledge(CTR_IRQ_TIMER_0 + timer); 31 | 32 | ctr_timer_set_value(timer, 0); 33 | ctr_timer_set_prescaler(timer, CTR_TIMER_DIV1); 34 | clocks[timer] = clock; 35 | ctr_irq_register(CTR_IRQ_TIMER_0 + timer, ctr_system_clock_interrupt_handler, (void*)timer); 36 | clock->timer = timer; 37 | clock->count = 0; 38 | 39 | active_clocks |= 1u << timer; 40 | 41 | ctr_timer_enable_irq(timer); 42 | ctr_timer_enable(timer); 43 | ctr_irq_enable(CTR_IRQ_TIMER_0 + timer); 44 | } 45 | } 46 | 47 | uint64_t ctr_system_clock_get_ms(ctr_system_clock *clock) 48 | { 49 | ctr_irq_critical_enter(); 50 | uint64_t timestamp = clock->count; 51 | ctr_irq_critical_exit(); 52 | 53 | uint32_t freq = ctr_timer_get_effective_frequency(clock->timer); 54 | return timestamp * 1000u / (freq / (1u << 16)) ; 55 | } 56 | 57 | ctr_clock_time ctr_system_clock_get_time(ctr_system_clock *clock) 58 | { 59 | ctr_irq_critical_enter(); 60 | uint64_t timestamp = clock->count; 61 | uint32_t reg = ctr_timer_get_value(clock->timer); 62 | ctr_irq_critical_exit(); 63 | 64 | uint32_t freq = ctr_timer_get_effective_frequency(clock->timer); 65 | ctr_clock_time result; 66 | uint32_t period = freq / (1u << 16); 67 | result.seconds = (int64_t)timestamp / period ; 68 | result.nanoseconds = ((uint64_t)timestamp - (uint64_t)result.seconds * period) * 1000000000u / period; 69 | result.nanoseconds += (int64_t)reg * 1000000000u / freq; 70 | return result; 71 | } 72 | 73 | static inline void ctr_system_clock_interrupt(ctr_timer timer) 74 | { 75 | if ((timer < 4u) && (active_clocks & (1u << timer))) 76 | { 77 | clocks[timer]->count += 1u; 78 | } 79 | ctr_irq_acknowledge(CTR_IRQ_TIMER_0 + timer); 80 | } 81 | 82 | static void ctr_system_clock_interrupt_handler(void *data) 83 | { 84 | ctr_timer timer = (ctr_timer)data; 85 | ctr_system_clock_interrupt(timer); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/ctr_timer.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define CTR_TIMER_REGISTER ((uint16_t(*)[2])(CTR_TIMER_REG_BASE)) 14 | 15 | void ctr_timer_set_value(ctr_timer timer, uint16_t value) 16 | { 17 | if (timer > 3) 18 | return; 19 | 20 | CTR_TIMER_REGISTER[timer][0] = value; 21 | } 22 | 23 | uint16_t ctr_timer_get_value(ctr_timer timer) 24 | { 25 | if (timer > 3) 26 | return 0; 27 | 28 | return CTR_TIMER_REGISTER[timer][0]; 29 | } 30 | 31 | bool ctr_timer_get_irq_state(ctr_timer timer) 32 | { 33 | if (timer > 3) 34 | return false; 35 | return CTR_TIMER_REGISTER[timer][1] & 0x0040; 36 | } 37 | 38 | void ctr_timer_enable_irq(ctr_timer timer) 39 | { 40 | if (timer > 3) 41 | return; 42 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 43 | ctrl |= 1u << 6; 44 | CTR_TIMER_REGISTER[timer][1] = ctrl; 45 | } 46 | 47 | void ctr_timer_disable_irq(ctr_timer timer) 48 | { 49 | if (timer > 3) 50 | return; 51 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 52 | ctrl &= ~0x0040u; 53 | CTR_TIMER_REGISTER[timer][1] = ctrl; 54 | } 55 | 56 | bool ctr_timer_get_state(ctr_timer timer) 57 | { 58 | if (timer > 3) 59 | return false; 60 | return CTR_TIMER_REGISTER[timer][2] & 0x0080; 61 | } 62 | 63 | void ctr_timer_enable(ctr_timer timer) 64 | { 65 | if (timer > 3) 66 | return; 67 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 68 | ctrl |= 1u << 7; 69 | CTR_TIMER_REGISTER[timer][1] = ctrl; 70 | } 71 | 72 | void ctr_timer_disable(ctr_timer timer) 73 | { 74 | if (timer > 3) 75 | return; 76 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 77 | ctrl &= ~0x0080u; 78 | CTR_TIMER_REGISTER[timer][1] = ctrl; 79 | } 80 | 81 | bool ctr_timer_get_count_up(ctr_timer timer) 82 | { 83 | if (timer > 3) 84 | return false; 85 | return CTR_TIMER_REGISTER[timer][1] & 0x0004; 86 | } 87 | 88 | void ctr_timer_set_count_up(ctr_timer timer, bool enable) 89 | { 90 | if (timer > 3) 91 | return; 92 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 93 | ctrl &= ~0x0004u; 94 | ctrl |= enable << 2; 95 | CTR_TIMER_REGISTER[timer][1] = ctrl; 96 | } 97 | 98 | void ctr_timer_set_prescaler(ctr_timer timer, ctr_timer_prescaler setting) 99 | { 100 | if (timer > 3) 101 | return; 102 | 103 | uint16_t ctrl = CTR_TIMER_REGISTER[timer][1]; 104 | ctrl &= ~0x3; 105 | ctrl |= setting & 0x3; 106 | CTR_TIMER_REGISTER[timer][1] = ctrl; 107 | } 108 | 109 | ctr_timer_prescaler ctr_timer_get_prescaler(ctr_timer timer) 110 | { 111 | if (timer > 3) 112 | return CTR_TIMER_DIV_UNKNOWN; 113 | 114 | return CTR_TIMER_REGISTER[timer][1] & 0x3; 115 | } 116 | 117 | uint32_t ctr_timer_get_effective_frequency(ctr_timer timer) 118 | { 119 | uint32_t divider; 120 | switch (ctr_timer_get_prescaler(timer)) 121 | { 122 | case CTR_TIMER_DIV1: 123 | divider = 1; 124 | break; 125 | case CTR_TIMER_DIV64: 126 | divider = 64; 127 | break; 128 | case CTR_TIMER_DIV256: 129 | divider = 256; 130 | break; 131 | case CTR_TIMER_DIV1024: 132 | divider = 1024; 133 | break; 134 | case CTR_TIMER_DIV_UNKNOWN: 135 | default: 136 | return 0; 137 | } 138 | 139 | return CTR_TIMER_FREQ / divider; 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/fatfs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.12 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | history.txt Revision history. 8 | ffconf.h Configuration file for FatFs module. 9 | ff.h Common include file for FatFs and application module. 10 | ff.c FatFs module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | option Optional external functions. 15 | 16 | 17 | Low level disk I/O module is not included in this archive because the FatFs 18 | module is only a generic file system layer and not depend on any specific 19 | storage device. You have to provide a low level disk I/O module that written 20 | to control the target storage device. 21 | 22 | -------------------------------------------------------------------------------- /src/fatfs/ctr_fatfs_disk.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2016 Gabriel Marcano 3 | * 4 | * Refer to the COPYING.txt file at the top of the project directory. If that is 5 | * missing, this file is licensed under the GPL version 2.0 or later. 6 | * 7 | ******************************************************************************/ 8 | 9 | #include 10 | #include 11 | 12 | void ctr_fatfs_default_setup(ctr_nand_crypto_interface *ctr_io, ctr_nand_crypto_interface *twl_io, ctr_sd_interface *sd_io) 13 | { 14 | ctr_setup_disk_parameters params; 15 | if (ctr_io) 16 | { 17 | if (ctr_get_system_type() == SYSTEM_O3DS) 18 | { 19 | params = (ctr_setup_disk_parameters){ctr_io, 0x0B930000/0x200, 0x2F5D0000/0x200}; 20 | } 21 | else 22 | { 23 | params = (ctr_setup_disk_parameters){ctr_io, 0x0B930000/0x200, 0x41ED0000/0x200}; 24 | } 25 | disk_ioctl_(0, CTR_SETUP_DISK, ¶ms); 26 | } 27 | 28 | if (twl_io) 29 | { 30 | params = (ctr_setup_disk_parameters){twl_io, 0x00012E00/0x200, 0x08FB5200/0x200 }; 31 | disk_ioctl_(1, CTR_SETUP_DISK, ¶ms); 32 | 33 | params = (ctr_setup_disk_parameters){twl_io, 0x09011A00/0x200, 0x020B6600/0x200}; 34 | disk_ioctl_(2, CTR_SETUP_DISK, ¶ms); 35 | } 36 | 37 | if (sd_io) 38 | { 39 | params = (ctr_setup_disk_parameters){sd_io, 0, ctr_io_disk_size(sd_io) / ctr_io_sector_size(sd_io)}; 40 | disk_ioctl_(3, CTR_SETUP_DISK, ¶ms); 41 | } 42 | } 43 | 44 | void ctr_fatfs_disk_initialize(ctr_fatfs_disk *disk, void *io, size_t sector_offset, size_t sectors) 45 | { 46 | *disk = (ctr_fatfs_disk){io, sector_offset, sectors, STA_NOINIT}; 47 | } 48 | 49 | void ctr_fatfs_disk_destroy(ctr_fatfs_disk *disk) 50 | { 51 | *disk = (ctr_fatfs_disk){ NULL, 0, 0, STA_NOINIT}; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/fatfs/option/syscall.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample code of OS dependent controls for FatFs */ 3 | /* (C)ChaN, 2014 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "../ff.h" 8 | 9 | 10 | #if _FS_REENTRANT 11 | /*------------------------------------------------------------------------*/ 12 | /* Create a Synchronization Object */ 13 | /*------------------------------------------------------------------------*/ 14 | /* This function is called in f_mount() function to create a new 15 | / synchronization object, such as semaphore and mutex. When a 0 is returned, 16 | / the f_mount() function fails with FR_INT_ERR. 17 | */ 18 | 19 | int ff_cre_syncobj_ ( /* 1:Function succeeded, 0:Could not create the sync object */ 20 | BYTE vol, /* Corresponding volume (logical drive number) */ 21 | _SYNC_t *sobj /* Pointer to return the created sync object */ 22 | ) 23 | { 24 | int ret; 25 | 26 | 27 | *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */ 28 | ret = (int)(*sobj != INVALID_HANDLE_VALUE); 29 | 30 | // *sobj = SyncObjects[vol]; /* uITRON (give a static sync object) */ 31 | // ret = 1; /* The initial value of the semaphore must be 1. */ 32 | 33 | // *sobj = OSMutexCreate(0, &err); /* uC/OS-II */ 34 | // ret = (int)(err == OS_NO_ERR); 35 | 36 | // *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */ 37 | // ret = (int)(*sobj != NULL); 38 | 39 | return ret; 40 | } 41 | 42 | 43 | 44 | /*------------------------------------------------------------------------*/ 45 | /* Delete a Synchronization Object */ 46 | /*------------------------------------------------------------------------*/ 47 | /* This function is called in f_mount() function to delete a synchronization 48 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 49 | / the f_mount() function fails with FR_INT_ERR. 50 | */ 51 | 52 | int ff_del_syncobj_ ( /* 1:Function succeeded, 0:Could not delete due to any error */ 53 | _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 54 | ) 55 | { 56 | int ret; 57 | 58 | 59 | ret = CloseHandle(sobj); /* Win32 */ 60 | 61 | // ret = 1; /* uITRON (nothing to do) */ 62 | 63 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */ 64 | // ret = (int)(err == OS_NO_ERR); 65 | 66 | // vSemaphoreDelete(sobj); /* FreeRTOS */ 67 | // ret = 1; 68 | 69 | return ret; 70 | } 71 | 72 | 73 | 74 | /*------------------------------------------------------------------------*/ 75 | /* Request Grant to Access the Volume */ 76 | /*------------------------------------------------------------------------*/ 77 | /* This function is called on entering file functions to lock the volume. 78 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 79 | */ 80 | 81 | int ff_req_grant_ ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 82 | _SYNC_t sobj /* Sync object to wait */ 83 | ) 84 | { 85 | int ret; 86 | 87 | ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */ 88 | 89 | // ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */ 90 | 91 | // OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */ 92 | // ret = (int)(err == OS_NO_ERR); 93 | 94 | // ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */ 95 | 96 | return ret; 97 | } 98 | 99 | 100 | 101 | /*------------------------------------------------------------------------*/ 102 | /* Release Grant to Access the Volume */ 103 | /*------------------------------------------------------------------------*/ 104 | /* This function is called on leaving file functions to unlock the volume. 105 | */ 106 | 107 | void ff_rel_grant_ ( 108 | _SYNC_t sobj /* Sync object to be signaled */ 109 | ) 110 | { 111 | ReleaseMutex(sobj); /* Win32 */ 112 | 113 | // sig_sem(sobj); /* uITRON */ 114 | 115 | // OSMutexPost(sobj); /* uC/OS-II */ 116 | 117 | // xSemaphoreGive(sobj); /* FreeRTOS */ 118 | } 119 | 120 | #endif 121 | 122 | 123 | 124 | 125 | #if _USE_LFN == 3 /* LFN with a working buffer on the heap */ 126 | /*------------------------------------------------------------------------*/ 127 | /* Allocate a memory block */ 128 | /*------------------------------------------------------------------------*/ 129 | /* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. 130 | */ 131 | 132 | void* ff_memalloc_ ( /* Returns pointer to the allocated memory block */ 133 | UINT msize /* Number of bytes to allocate */ 134 | ) 135 | { 136 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 137 | } 138 | 139 | 140 | /*------------------------------------------------------------------------*/ 141 | /* Free a memory block */ 142 | /*------------------------------------------------------------------------*/ 143 | 144 | void ff_memfree_ ( 145 | void* mblock /* Pointer to the memory block to free */ 146 | ) 147 | { 148 | free(mblock); /* Discard the memory block with POSIX API */ 149 | } 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /src/fatfs/option/unicode.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if _USE_LFN != 0 4 | 5 | #if _CODE_PAGE == 932 /* Japanese Shift_JIS */ 6 | #include "cc932.c" 7 | #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ 8 | #include "cc936.c" 9 | #elif _CODE_PAGE == 949 /* Korean */ 10 | #include "cc949.c" 11 | #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ 12 | #include "cc950.c" 13 | #else /* Single Byte Character-Set */ 14 | #include "ccsbcs.c" 15 | #endif 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/gamecart/command_ctr.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | static int read_count = 0; 12 | 13 | static void CTR_CmdC5() 14 | { 15 | static const uint32_t c5_cmd[4] = { 0xC5000000, 0x00000000, 0x00000000, 0x00000000 }; 16 | CTR_SendCommand(c5_cmd, 0, 1, 0x100002C, NULL); 17 | } 18 | 19 | void CTR_CmdReadData(uint32_t sector, uint32_t length, uint32_t blocks, void* buffer) 20 | { 21 | if(read_count++ > 10000) 22 | { 23 | CTR_CmdC5(); 24 | read_count = 0; 25 | } 26 | 27 | const uint32_t read_cmd[4] = { 28 | (0xBF000000 | (uint32_t)(sector >> 23)), 29 | (uint32_t)((sector << 9) & 0xFFFFFFFF), 30 | 0x00000000, 0x00000000 31 | }; 32 | CTR_SendCommand(read_cmd, length, blocks, 0x704822C, buffer); 33 | } 34 | 35 | void CTR_CmdReadHeader(void* buffer) 36 | { 37 | static const uint32_t readheader_cmd[4] = { 0x82000000, 0x00000000, 0x00000000, 0x00000000 }; 38 | CTR_SendCommand(readheader_cmd, 0x200, 1, 0x704802C, buffer); 39 | } 40 | 41 | uint32_t CTR_CmdGetSecureId(uint32_t rand1, uint32_t rand2) 42 | { 43 | uint32_t id = 0; 44 | const uint32_t getid_cmd[4] = { 0xA2000000, 0x00000000, rand1, rand2 }; 45 | CTR_SendCommand(getid_cmd, 0x4, 1, 0x701002C, &id); 46 | return id; 47 | } 48 | 49 | void CTR_CmdSeed(uint32_t rand1, uint32_t rand2) 50 | { 51 | const uint32_t seed_cmd[4] = { 0x83000000, 0x00000000, rand1, rand2 }; 52 | CTR_SendCommand(seed_cmd, 0, 1, 0x700822C, NULL); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/gamecart/command_ntr.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | void NTR_CmdReset(void) 12 | { 13 | static const uint32_t reset_cmd[2] = { 0x9F000000, 0x00000000 }; 14 | NTR_SendCommand(reset_cmd, 0x2000, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), NULL); 15 | } 16 | 17 | uint32_t NTR_CmdGetCartId(void) 18 | { 19 | uint32_t id; 20 | static const uint32_t getid_cmd[2] = { 0x90000000, 0x00000000 }; 21 | NTR_SendCommand(getid_cmd, 0x4, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), &id); 22 | return id; 23 | } 24 | 25 | void NTR_CmdEnter16ByteMode(void) 26 | { 27 | static const uint32_t enter16bytemode_cmd[2] = { 0x3E000000, 0x00000000 }; 28 | NTR_SendCommand(enter16bytemode_cmd, 0x0, 0, NULL); 29 | } 30 | -------------------------------------------------------------------------------- /src/gamecart/delay.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include "common.h" 8 | 9 | void ioDelay(u32 us); 10 | -------------------------------------------------------------------------------- /src/gamecart/delay.s: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | .arm 6 | .global ioDelay 7 | .type ioDelay STT_FUNC 8 | 9 | @ioDelay ( u32 us ) 10 | ioDelay: 11 | ldr r1, =0x18000000 @ VRAM 12 | 1: 13 | @ Loop doing uncached reads from VRAM to make loop timing more reliable 14 | ldr r2, [r1] 15 | subs r0, #1 16 | bgt 1b 17 | bx lr 18 | -------------------------------------------------------------------------------- /src/gamecart/protocol_ntr.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | void NTR_SendCommand(const uint32_t command[2], uint32_t pageSize, uint32_t latency, void* buffer) 11 | { 12 | #ifdef VERBOSE_COMMANDS 13 | Debug("N> %08X %08X", command[0], command[1]); 14 | #endif 15 | 16 | REG_NTRCARDMCNT = NTRCARD_CR1_ENABLE; 17 | 18 | for( uint32_t i=0; i<2; ++i ) 19 | { 20 | REG_NTRCARDCMD[i*4+0] = command[i]>>24; 21 | REG_NTRCARDCMD[i*4+1] = command[i]>>16; 22 | REG_NTRCARDCMD[i*4+2] = command[i]>>8; 23 | REG_NTRCARDCMD[i*4+3] = command[i]>>0; 24 | } 25 | 26 | pageSize -= pageSize & 3; // align to 4 byte 27 | 28 | uint32_t pageParam = NTRCARD_PAGESIZE_4K; 29 | uint32_t transferLength = 4096; 30 | 31 | // make zero read and 4 byte read a little special for timing optimization(and 512 too) 32 | switch (pageSize) { 33 | case 0: 34 | transferLength = 0; 35 | pageParam = NTRCARD_PAGESIZE_0; 36 | break; 37 | case 4: 38 | transferLength = 4; 39 | pageParam = NTRCARD_PAGESIZE_4; 40 | break; 41 | case 512: 42 | transferLength = 512; 43 | pageParam = NTRCARD_PAGESIZE_512; 44 | break; 45 | case 8192: 46 | transferLength = 8192; 47 | pageParam = NTRCARD_PAGESIZE_8K; 48 | break; 49 | default: 50 | break; //Using 4K pagesize and transfer length by default 51 | } 52 | 53 | // go 54 | REG_NTRCARDROMCNT = 0x10000000; 55 | REG_NTRCARDROMCNT = NTRKEY_PARAM | NTRCARD_ACTIVATE | NTRCARD_nRESET | pageParam | latency; 56 | 57 | uint8_t * pbuf = (uint8_t *)buffer; 58 | uint32_t * pbuf32 = (uint32_t * )buffer; 59 | bool useBuf = ( NULL != pbuf ); 60 | bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)buffer)))); 61 | 62 | uint32_t count = 0; 63 | uint32_t cardCtrl = REG_NTRCARDROMCNT; 64 | 65 | if(useBuf32) 66 | { 67 | while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) 68 | { 69 | cardCtrl = REG_NTRCARDROMCNT; 70 | if( cardCtrl & NTRCARD_DATA_READY ) { 71 | uint32_t data = REG_NTRCARDFIFO; 72 | *pbuf32++ = data; 73 | count += 4; 74 | } 75 | } 76 | } 77 | else if(useBuf) 78 | { 79 | while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) 80 | { 81 | cardCtrl = REG_NTRCARDROMCNT; 82 | if( cardCtrl & NTRCARD_DATA_READY ) { 83 | uint32_t data = REG_NTRCARDFIFO; 84 | pbuf[0] = (unsigned char) (data >> 0); 85 | pbuf[1] = (unsigned char) (data >> 8); 86 | pbuf[2] = (unsigned char) (data >> 16); 87 | pbuf[3] = (unsigned char) (data >> 24); 88 | pbuf += sizeof (unsigned int); 89 | count += 4; 90 | } 91 | } 92 | } 93 | else 94 | { 95 | while( (cardCtrl & NTRCARD_BUSY) && count < pageSize) 96 | { 97 | cardCtrl = REG_NTRCARDROMCNT; 98 | if( cardCtrl & NTRCARD_DATA_READY ) { 99 | uint32_t data = REG_NTRCARDFIFO; 100 | (void)data; 101 | count += 4; 102 | } 103 | } 104 | } 105 | 106 | // if read is not finished, ds will not pull ROM CS to high, we pull it high manually 107 | if( count != transferLength ) { 108 | // MUST wait for next data ready, 109 | // if ds pull ROM CS to high during 4 byte data transfer, something will mess up 110 | // so we have to wait next data ready 111 | do { cardCtrl = REG_NTRCARDROMCNT; } while(!(cardCtrl & NTRCARD_DATA_READY)); 112 | // and this tiny delay is necessary 113 | //ioAK2Delay(33); 114 | // pull ROM CS high 115 | REG_NTRCARDROMCNT = 0x10000000; 116 | REG_NTRCARDROMCNT = NTRKEY_PARAM | NTRCARD_ACTIVATE | NTRCARD_nRESET/* | 0 | 0x0000*/; 117 | } 118 | // wait rom cs high 119 | do { cardCtrl = REG_NTRCARDROMCNT; } while( cardCtrl & NTRCARD_BUSY ); 120 | //lastCmd[0] = command[0];lastCmd[1] = command[1]; 121 | 122 | #ifdef VERBOSE_COMMANDS 123 | if (!useBuf) { 124 | Debug("N< NULL"); 125 | } else if (!useBuf32) { 126 | Debug("N< non32"); 127 | } else { 128 | uint32_t* p = (uint32_t*)buffer; 129 | int transferWords = count / 4; 130 | for (int i = 0; i < transferWords && i < 4*4; i += 4) { 131 | switch (transferWords - i) { 132 | case 0: 133 | break; 134 | case 1: 135 | Debug("N< %08X", p[i+0]); 136 | break; 137 | case 2: 138 | Debug("N< %08X %08X", p[i+0], p[i+1]); 139 | break; 140 | case 3: 141 | Debug("N< %08X %08X %08X", p[i+0], p[i+1], p[i+2]); 142 | break; 143 | default: 144 | Debug("N< %08X %08X %08X %08X", p[i+0], p[i+1], p[i+2], p[i+3]); 145 | break; 146 | } 147 | } 148 | } 149 | #endif 150 | } 151 | -------------------------------------------------------------------------------- /src/i2c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void i2cStop(uint8_t bus_id, uint8_t arg0) { 5 | ctr_core_i2cStop(bus_id, arg0); 6 | } 7 | 8 | //----------------------------------------------------------------------------- 9 | 10 | bool i2cSelectDevice(uint8_t bus_id, uint8_t dev_reg) { 11 | return ctr_core_i2cSelectDevice(bus_id, dev_reg); 12 | } 13 | 14 | bool i2cSelectRegister(uint8_t bus_id, uint8_t reg) { 15 | return ctr_core_i2cSelectRegister(bus_id, reg); 16 | } 17 | 18 | //----------------------------------------------------------------------------- 19 | 20 | uint8_t i2cReadRegister(uint8_t dev_id, uint8_t reg) { 21 | return ctr_core_i2cReadRegister(dev_id, reg); 22 | } 23 | 24 | bool i2cReadRegisterBuffer(uint8_t dev_id, uint8_t reg, uint8_t* buffer, size_t buf_size) { 25 | return ctr_core_i2cReadRegisterBuffer(dev_id, reg, buffer, buf_size); 26 | } 27 | 28 | bool i2cWriteRegister(uint8_t dev_id, uint8_t reg, uint8_t data) { 29 | return ctr_core_i2cWriteRegister(dev_id, reg, data); 30 | } 31 | 32 | bool i2cWriteRegisterBuffer(uint8_t dev_id, uint8_t reg, const uint8_t *buffer, size_t buf_size) { 33 | return ctr_core_i2cWriteRegisterBuffer(dev_id, reg, buffer, buf_size); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/sdmmc/delay.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .global waitcycles 3 | .type waitcycles STT_FUNC 4 | 5 | @waitcycles ( u32 us ) 6 | waitcycles: 7 | PUSH {R0-R2,LR} 8 | STR R0, [SP,#4] 9 | waitcycles_loop: 10 | LDR R3, [SP,#4] 11 | SUBS R2, R3, #1 12 | STR R2, [SP,#4] 13 | CMP R3, #0 14 | BNE waitcycles_loop 15 | POP {R0-R2,PC} 16 | -------------------------------------------------------------------------------- /src/sha.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void sha_init(uint32_t mode) 5 | { 6 | while(*REG_SHACNT & 1); 7 | *REG_SHACNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; 8 | } 9 | 10 | void sha_update(const void* src, uint32_t size) 11 | { 12 | const uint32_t* src32 = (const uint32_t*)src; 13 | 14 | while(size >= 0x40) { 15 | while(*REG_SHACNT & 1); 16 | for(uint32_t i = 0; i < 4; i++) { 17 | *REG_SHAINFIFO = *src32++; 18 | *REG_SHAINFIFO = *src32++; 19 | *REG_SHAINFIFO = *src32++; 20 | *REG_SHAINFIFO = *src32++; 21 | } 22 | size -= 0x40; 23 | } 24 | while(*REG_SHACNT & 1); 25 | 26 | for(size_t i = 0; i < size; ++i) 27 | { 28 | ((volatile char*)REG_SHAINFIFO)[i] = ((const char*)src)[i]; 29 | } 30 | } 31 | 32 | void sha_get(void* res) { 33 | *REG_SHACNT = (*REG_SHACNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; 34 | while(*REG_SHACNT & SHA_FINAL_ROUND); 35 | while(*REG_SHACNT & 1); 36 | 37 | for (size_t i = 0; i < 256u/8u; ++i) 38 | { 39 | ((char*)res)[i] = ((volatile char*)REG_SHAHASH)[i]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | test.bin 2 | test 3 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | include $(top_srcdir)/common.mk 2 | 3 | EXTRA_PROGRAMS = test 4 | test_CFLAGS=$(AM_CFLAGS) -T$(srcdir)/arm9loaderhax.ld -L${prefix}/lib -I${prefix}/include/freetype2 #-nostartfiles 5 | test_SOURCES = main.c test.c test.h interrupt.c nand_tests.h nand_tests.c nand_crypto_tests.h nand_crypto_tests.c sd_tests.h sd_tests.c twl_tests.c twl_tests.h memory_tests.h memory_tests.c crypto_memory_tests.h crypto_memory_tests.c memory_control_tests.c memory_control_tests.h 6 | test_LDADD = $(AM_LDADD) $(top_builddir)/src/libctr9.la -lctr_core -lfreetype -lm 7 | 8 | EXTRA_DIST = arm9loaderhax.ld 9 | 10 | .PHONY: FORCE 11 | 12 | FORCE: 13 | 14 | $(top_builddir)/src/libctr9.la: FORCE 15 | (cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) libctr9.la ) 16 | 17 | clean-local: 18 | rm -f test 19 | rm -f test.bin 20 | 21 | test.bin: test 22 | cp test test.bin 23 | arm-none-eabi-strip test.bin 24 | 25 | -------------------------------------------------------------------------------- /test/crypto_memory_tests.c: -------------------------------------------------------------------------------- 1 | #include "crypto_memory_tests.h" 2 | 3 | #include "nand_crypto_tests.h" 4 | 5 | #include 6 | 7 | static bool crypto_memory_test1(void *ctx) 8 | { 9 | nand_crypto_test_data *data = ctx; 10 | int res = ctr_nand_crypto_interface_initialize(&data->io, 0x04, NAND_CTR, data->lower_io); 11 | 12 | return !res; 13 | } 14 | 15 | static bool crypto_memory_test2(void *ctx) 16 | { 17 | nand_crypto_test_data *data = ctx; 18 | char *buffer = data->buffer; 19 | size_t buffer_size = data->buffer_size; 20 | 21 | ctr_nand_interface nand_io; 22 | ctr_nand_crypto_interface crypto_io; 23 | 24 | ctr_nand_interface_initialize(&nand_io); 25 | ctr_nand_crypto_interface_initialize(&crypto_io, 0x04, NAND_CTR, &nand_io.base); 26 | 27 | ctr_io_read_sector(&nand_io, ((ctr_memory_interface*)(data->io.crypto_io.lower_io))->buffer, ((ctr_memory_interface*)(data->io.crypto_io.lower_io))->buffer_size, 0, 1); 28 | char buffer2[512]; 29 | ctr_io_read_sector(&crypto_io, buffer2, sizeof(buffer2), 0, 1); 30 | 31 | int res = ctr_nand_crypto_interface_read_sector(&data->io, buffer, buffer_size, 55, 55); 32 | 33 | return !res && memcmp(buffer, buffer2 + 55, 55) == 0; 34 | } 35 | 36 | static bool crypto_memory_test3(void *ctx) 37 | { 38 | nand_crypto_test_data *data = ctx; 39 | char *buffer = data->buffer; 40 | size_t buffer_size = data->buffer_size; 41 | int res = ctr_nand_crypto_interface_read(&data->io, buffer, buffer_size, 55, 55); 42 | 43 | return !res; 44 | } 45 | 46 | static bool crypto_memory_test4(void *ctx) 47 | { 48 | nand_crypto_test_data *data = ctx; 49 | uint8_t stuff[0x200]; 50 | for (size_t i = 0; i < sizeof(stuff); ++i) 51 | stuff[i] = 255-i; 52 | 53 | int res = ctr_nand_crypto_interface_write_sector(&data->io, stuff, sizeof(stuff), 0x0); 54 | uint8_t stuff2[sizeof(stuff)]; 55 | res |= ctr_nand_crypto_interface_read_sector(&data->io, stuff2, sizeof(stuff2), 0x0, sizeof(stuff2)); 56 | 57 | bool result = !memcmp(stuff, stuff2, sizeof(stuff)); 58 | return !res && result; 59 | } 60 | 61 | static bool crypto_memory_test5(void *ctx) 62 | { 63 | nand_crypto_test_data *data = ctx; 64 | uint8_t stuff[0x200]; 65 | for (size_t i = 0; i < sizeof(stuff); ++i) 66 | stuff[i] = 255-i; 67 | 68 | int res = ctr_nand_crypto_interface_write(&data->io, stuff, 5, 10); 69 | uint8_t stuff2[sizeof(stuff)]; 70 | res |= ctr_nand_crypto_interface_read(&data->io, stuff2, sizeof(stuff2), 10, sizeof(stuff2)-5); 71 | 72 | bool result = !memcmp(stuff, stuff2, 5); 73 | return !res && result; 74 | } 75 | 76 | void crypto_memory_tests_initialize(ctr_unit_tests *crypto_memory_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *crypto_memory_ctx) 77 | { 78 | ctr_unit_tests_initialize(crypto_memory_tests, "ctr crypto io memory tests", funcs, 5); 79 | ctr_unit_tests_add_test(crypto_memory_tests, (ctr_unit_test){ "crypto memory_initialize", crypto_memory_ctx, crypto_memory_test1 }); 80 | ctr_unit_tests_add_test(crypto_memory_tests, (ctr_unit_test){ "crypto memory_read_sector", crypto_memory_ctx, crypto_memory_test2 }); 81 | ctr_unit_tests_add_test(crypto_memory_tests, (ctr_unit_test){ "crypto memory_read", crypto_memory_ctx, crypto_memory_test3 }); 82 | ctr_unit_tests_add_test(crypto_memory_tests, (ctr_unit_test){ "crypto memory_write_sector", crypto_memory_ctx, crypto_memory_test4 }); 83 | ctr_unit_tests_add_test(crypto_memory_tests, (ctr_unit_test){ "crypto memory_write", crypto_memory_ctx, crypto_memory_test5 }); 84 | } 85 | -------------------------------------------------------------------------------- /test/crypto_memory_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_CRYPTO_MEMORY_TESTS_H_ 2 | #define CTR_CRYPTO_MEMORY_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | 7 | void crypto_memory_tests_initialize(ctr_unit_tests *crypto_memory_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *crypto_memory_ctx); 8 | 9 | #endif//CTR_CRYPTO_MEMORY_TESTS_H_ 10 | 11 | -------------------------------------------------------------------------------- /test/interrupt.c: -------------------------------------------------------------------------------- 1 | #include "interrupt.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #ifdef __thumb__ 11 | //#error 12 | #endif 13 | 14 | static void print_all_registers(uint32_t *registers) 15 | { 16 | uint32_t cpsr = registers[0]; 17 | uint32_t sp = registers[1]; 18 | uint32_t lr = registers[2]; 19 | uint32_t ret = registers[3]; 20 | const uint32_t *r = registers+4; 21 | 22 | printf("CPSR: 0x%08"PRIX32"\n", cpsr); 23 | printf("SP: 0x%08"PRIX32"\n", sp); 24 | printf("LR: 0x%08"PRIX32"\n", lr); 25 | printf("Abort address: 0x%08"PRIXPTR"\n", (uintptr_t)(ret - 8)); 26 | for (size_t i = 0; i < 13; ++i) 27 | { 28 | printf("r%d: 0x%08"PRIX32"\n", i, r[i]); 29 | } 30 | } 31 | 32 | void abort_interrupt(uint32_t *registers, void *data) 33 | { 34 | printf("\n\nDATA ABORT:\n"); 35 | 36 | print_all_registers(registers); 37 | ctr_input_wait(); 38 | 39 | uint32_t cpsr = registers[0]; 40 | if (cpsr & 0x20) 41 | { 42 | registers[3] -= 6; 43 | printf("Ret. Thumb: 0x%08"PRIX32"\n", registers[3]); 44 | } 45 | else 46 | { 47 | registers[3] -= 4; 48 | printf("Ret. ARM: 0x%08"PRIX32"\n", registers[3]); 49 | } 50 | } 51 | 52 | void undefined_instruction(uint32_t *registers, void *data) 53 | { 54 | printf("\n\nUNDEFINED INSTRUCTION:\n"); 55 | 56 | print_all_registers(registers); 57 | ctr_input_wait(); 58 | ctr_system_poweroff(); 59 | } 60 | 61 | void prefetch_abort(uint32_t *registers, void *data) 62 | { 63 | printf("\n\nPREFETCH ABORT:\n"); 64 | 65 | print_all_registers(registers); 66 | ctr_input_wait(); 67 | ctr_system_poweroff(); 68 | } 69 | 70 | -------------------------------------------------------------------------------- /test/interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_TEST_INTERRUPT_H_ 2 | #define CTR_TEST_INTERRUPT_H_ 3 | 4 | #include 5 | 6 | void abort_interrupt(uint32_t *registers, void *data); 7 | void undefined_instruction(uint32_t *registers, void *data); 8 | void prefetch_abort(uint32_t *registers, void *data); 9 | 10 | #endif//CTR_TEST_INTERRUPT_H_ 11 | 12 | -------------------------------------------------------------------------------- /test/memory_control_tests.c: -------------------------------------------------------------------------------- 1 | #include "memory_control_tests.h" 2 | #include 3 | #include 4 | 5 | //FIXME Need to make unit tests take into acconut when being run in an N3DS, since some region and size commands are impacted. 6 | 7 | static bool memory_control_test1(void *ctx) 8 | { 9 | if (CTR_MEMORY_ITCM_REGION != ctr_memory_get_region(0x0)) 10 | return false; 11 | if (CTR_MEMORY_ARM9_REGION != ctr_memory_get_region(0x08000000)) 12 | return false; 13 | if (CTR_MEMORY_ARM9_REGION != ctr_memory_get_region(0x080FFFFF)) 14 | return false; 15 | if (CTR_MEMORY_UNKNOWN_REGION != ctr_memory_get_region(0x08100000)) 16 | return false; 17 | if (CTR_MEMORY_IO_REGION != ctr_memory_get_region(0x10000000)) 18 | return false; 19 | if (CTR_MEMORY_IO_REGION != ctr_memory_get_region(0x17FFFFFF)) 20 | return false; 21 | if (CTR_MEMORY_VRAM_REGION != ctr_memory_get_region(0x18000000)) 22 | return false; 23 | if (CTR_MEMORY_VRAM_REGION != ctr_memory_get_region(0x185FFFFF)) 24 | return false; 25 | if (CTR_MEMORY_UNKNOWN_REGION != ctr_memory_get_region(0x18600000)) 26 | return false; 27 | if (CTR_MEMORY_DSP_REGION != ctr_memory_get_region(0x1FF00000)) 28 | return false; 29 | if (CTR_MEMORY_DSP_REGION != ctr_memory_get_region(0x1FF7FFFF)) 30 | return false; 31 | if (CTR_MEMORY_AXI_WRAM_REGION != ctr_memory_get_region(0x1FF80000)) 32 | return false; 33 | if (CTR_MEMORY_AXI_WRAM_REGION != ctr_memory_get_region(0x1FFFFFFF)) 34 | return false; 35 | if (CTR_MEMORY_FCRAM_REGION != ctr_memory_get_region(0x20000000)) 36 | return false; 37 | if (CTR_MEMORY_FCRAM_REGION != ctr_memory_get_region(0x27FFFFFF)) 38 | return false; 39 | //if (CTR_MEMORY__REGION != ctr_memory_get_region(0x28000000)) 40 | // return false; 41 | if (CTR_MEMORY_DTCM_REGION != ctr_memory_get_region(0x30000000)) 42 | return false; 43 | if (CTR_MEMORY_DTCM_REGION != ctr_memory_get_region(0x30003FFF)) 44 | return false; 45 | if (CTR_MEMORY_UNKNOWN_REGION != ctr_memory_get_region(0x30004FFF)) 46 | return false; 47 | if (CTR_MEMORY_BOOTROM_REGION != ctr_memory_get_region(0xFFFF0000)) 48 | return false; 49 | if (CTR_MEMORY_BOOTROM_REGION != ctr_memory_get_region(0xFFFFFFFF)) 50 | return false; 51 | 52 | return true; 53 | } 54 | 55 | static bool memory_control_test2(void *ctx) 56 | { 57 | ctr_memory_set_dtcm_state(false); 58 | if (ctr_memory_dtcm_state()) 59 | return false; 60 | 61 | ctr_memory_set_itcm_state(false); 62 | if (ctr_memory_itcm_state()) 63 | return false; 64 | 65 | ctr_memory_set_dtcm_state(true); 66 | if (!ctr_memory_dtcm_state()) 67 | return false; 68 | 69 | ctr_memory_set_itcm_state(true); 70 | if (!ctr_memory_itcm_state()) 71 | return false; 72 | 73 | return true; 74 | } 75 | 76 | static bool memory_control_test3(void *ctx) 77 | { 78 | if (CTR_MEMORY_TCM_64MB != ctr_memory_itcm_size()) 79 | return false; 80 | if (CTR_MEMORY_TCM_16KB != ctr_memory_dtcm_size()) 81 | return false; 82 | 83 | ctr_memory_set_itcm_size(CTR_MEMORY_TCM_128MB); 84 | if (CTR_MEMORY_TCM_128MB != ctr_memory_itcm_size()) 85 | return false; 86 | 87 | ctr_memory_set_dtcm_size(CTR_MEMORY_TCM_32KB); 88 | if (CTR_MEMORY_TCM_32KB != ctr_memory_dtcm_size()) 89 | return false; 90 | 91 | ctr_memory_set_dtcm_size(CTR_MEMORY_TCM_16KB); 92 | ctr_memory_set_itcm_size(CTR_MEMORY_TCM_64MB); 93 | 94 | return true; 95 | } 96 | 97 | static bool memory_control_test4(void *ctx) 98 | { 99 | if (ctr_memory_dtcm_address() != 0x30000000) 100 | return false; 101 | 102 | ctr_memory_set_dtcm_address(0x45600000); 103 | if (ctr_memory_dtcm_address() != 0x45600000) 104 | return false; 105 | 106 | ctr_memory_set_dtcm_address(0x30000000); 107 | 108 | return true; 109 | } 110 | 111 | static bool memory_control_test5(void *ctx) 112 | { 113 | //if (ctr_memory_fcram_size() != 0x08000000) 114 | // return false; 115 | //if (ctr_memory_arm9_size() != 0x00100000) 116 | // return false; 117 | return true; 118 | } 119 | 120 | void memory_control_tests_initialize(ctr_unit_tests *memory_control_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *memory_control_ctx) 121 | { 122 | ctr_unit_tests_initialize(memory_control_tests, "ctr io memory control tests", funcs, 5); 123 | ctr_unit_tests_add_test(memory_control_tests, (ctr_unit_test){ "memory region check", memory_control_ctx, memory_control_test1 }); 124 | ctr_unit_tests_add_test(memory_control_tests, (ctr_unit_test){ "TCM state check", memory_control_ctx, memory_control_test2 }); 125 | ctr_unit_tests_add_test(memory_control_tests, (ctr_unit_test){ "TCM size check", memory_control_ctx, memory_control_test3 }); 126 | ctr_unit_tests_add_test(memory_control_tests, (ctr_unit_test){ "DTCM base address check", memory_control_ctx, memory_control_test4 }); 127 | ctr_unit_tests_add_test(memory_control_tests, (ctr_unit_test){ "Memory size checks", memory_control_ctx, memory_control_test5 }); 128 | } 129 | 130 | -------------------------------------------------------------------------------- /test/memory_control_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_MEMORY_CONTROL_TESTS_H_ 2 | #define CTR_MEMORY_CONTROL_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | char *buffer; 11 | size_t buffer_size; 12 | 13 | uint8_t data[0x1000]; 14 | ctr_memory_interface mem_io; 15 | } memory_control_test_data; 16 | 17 | void memory_control_tests_initialize(ctr_unit_tests *memory_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *memory_ctx); 18 | 19 | #endif//CTR_MEMORY_CONTROL_TESTS_H_ 20 | 21 | -------------------------------------------------------------------------------- /test/memory_tests.c: -------------------------------------------------------------------------------- 1 | #include "memory_tests.h" 2 | #include 3 | 4 | memory_test_data memory_test_data_initialize(char *buffer, size_t buffer_size) 5 | { 6 | memory_test_data data; 7 | data.buffer = buffer; 8 | data.buffer_size = buffer_size; 9 | return data; 10 | } 11 | 12 | static bool memory_test1(void *ctx) 13 | { 14 | memory_test_data *data = ctx; 15 | ctr_memory_interface_initialize(&data->mem_io, data->data, sizeof(data->data)); 16 | 17 | for (size_t i = 0; i < sizeof(data->data); ++i) 18 | data->data[i] = i; 19 | 20 | return true; 21 | } 22 | 23 | static bool memory_test2(void *ctx) 24 | { 25 | memory_test_data *data = ctx; 26 | char *buffer = data->buffer; 27 | size_t buffer_size = data->buffer_size; 28 | ctr_memory_interface_read_sector(&data->mem_io, buffer, buffer_size, 55, 55); 29 | 30 | for (size_t i = 0; i < 55; ++i) 31 | if (i+55 != buffer[i]) 32 | return false; 33 | 34 | return true; 35 | } 36 | 37 | static bool memory_test3(void *ctx) 38 | { 39 | memory_test_data *data = ctx; 40 | char *buffer = data->buffer; 41 | size_t buffer_size = data->buffer_size; 42 | ctr_memory_interface_read(&data->mem_io, buffer, buffer_size, 55, 55); 43 | 44 | for (size_t i = 0; i < 55; ++i) 45 | if (i+55 != buffer[i]) 46 | return false; 47 | 48 | return true; 49 | } 50 | 51 | static bool memory_test4(void *ctx) 52 | { 53 | memory_test_data *data = ctx; 54 | uint8_t stuff[0x200]; 55 | for (size_t i = 0; i < sizeof(stuff); ++i) 56 | stuff[i] = 255-i; 57 | 58 | ctr_memory_interface_write_sector(&data->mem_io, stuff, sizeof(stuff), 55); 59 | 60 | return (!memcmp((char*)data->mem_io.buffer + 55, stuff, sizeof(stuff))); 61 | } 62 | 63 | static bool memory_test5(void *ctx) 64 | { 65 | memory_test_data *data = ctx; 66 | uint8_t stuff[0x200]; 67 | for (size_t i = 0; i < sizeof(stuff); ++i) 68 | stuff[i] = 255-i; 69 | 70 | ctr_memory_interface_write(&data->mem_io, stuff, sizeof(stuff), 55); 71 | 72 | return (!memcmp((char*)data->mem_io.buffer + 55, stuff, sizeof(stuff))); 73 | } 74 | 75 | void memory_tests_initialize(ctr_unit_tests *memory_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *memory_ctx) 76 | { 77 | ctr_unit_tests_initialize(memory_tests, "ctr io memory tests", funcs, 5); 78 | ctr_unit_tests_add_test(memory_tests, (ctr_unit_test){ "memory_initialize", memory_ctx, memory_test1 }); 79 | ctr_unit_tests_add_test(memory_tests, (ctr_unit_test){ "memory_read_sector", memory_ctx, memory_test2 }); 80 | ctr_unit_tests_add_test(memory_tests, (ctr_unit_test){ "memory_read", memory_ctx, memory_test3 }); 81 | ctr_unit_tests_add_test(memory_tests, (ctr_unit_test){ "memory_write_sector", memory_ctx, memory_test4 }); 82 | ctr_unit_tests_add_test(memory_tests, (ctr_unit_test){ "memory_write", memory_ctx, memory_test5 }); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /test/memory_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_MEMORY_TESTS_H_ 2 | #define CTR_MEMORY_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | char *buffer; 11 | size_t buffer_size; 12 | 13 | uint8_t data[0x1000]; 14 | ctr_memory_interface mem_io; 15 | } memory_test_data; 16 | 17 | memory_test_data memory_test_data_initialize(char *buffer, size_t buffer_size); 18 | 19 | void memory_tests_initialize(ctr_unit_tests *memory_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *memory_ctx); 20 | 21 | #endif//CTR_MEMORY_TESTS_H_ 22 | 23 | -------------------------------------------------------------------------------- /test/nand_crypto_tests.c: -------------------------------------------------------------------------------- 1 | #include "nand_crypto_tests.h" 2 | #include 3 | 4 | #include 5 | 6 | nand_crypto_test_data nand_crypto_test_data_initialize(char *buffer, size_t buffer_size, ctr_io_interface *lower_io) 7 | { 8 | nand_crypto_test_data data; 9 | data.buffer = buffer; 10 | data.buffer_size = buffer_size; 11 | data.lower_io = lower_io; 12 | return data; 13 | } 14 | 15 | static bool nand_ctrnand_test1(void *ctx) 16 | { 17 | nand_crypto_test_data *data = ctx; 18 | 19 | int res = ctr_nand_crypto_interface_initialize(&data->io, 0x04, NAND_CTR, data->lower_io); 20 | 21 | return !res; 22 | } 23 | 24 | static bool nand_ctrnand_test2(void *ctx) 25 | { 26 | nand_crypto_test_data *data = ctx; 27 | char *buffer = data->buffer; 28 | size_t buffer_size = data->buffer_size; 29 | 30 | uint32_t loc = 0x0B95CA00/ 0x200; //CTRNAND 31 | int res = ctr_io_read_sector(&data->io, buffer, buffer_size, loc, 1); 32 | 33 | return !res && strncmp("CTR", buffer+3, 3) == 0; 34 | } 35 | 36 | static bool nand_ctrnand_test3(void *ctx) 37 | { 38 | nand_crypto_test_data *data = ctx; 39 | char *buffer = data->buffer; 40 | size_t buffer_size = data->buffer_size; 41 | 42 | uint32_t loc = 0x0B95CA00; //CTRNAND 43 | int res = ctr_io_read(&data->io, buffer, buffer_size, loc + 3, 3); 44 | 45 | return !res && strncmp("CTR", buffer, 3) == 0; 46 | } 47 | 48 | static bool nand_ctrnand_test4(void *ctx) 49 | { 50 | nand_crypto_test_data *data = ctx; 51 | char *buffer = data->buffer; 52 | size_t buffer_size = data->buffer_size; 53 | 54 | uint32_t loc = 0x0B95CA00; //CTRNAND 55 | 56 | int res = ctr_io_read(&data->io, buffer, buffer_size/2, loc, buffer_size/2); 57 | res |= ctr_io_read_sector(&data->io, buffer+buffer_size/2, buffer_size/2, loc /0x200, buffer_size/2/512); 58 | 59 | bool test1 = memcmp(buffer, buffer + buffer_size/2, buffer_size/2) == 0; 60 | 61 | res |= ctr_io_read(&data->io, buffer, buffer_size/2, loc+3, buffer_size/2-4); 62 | 63 | bool test2 = memcmp(buffer, buffer + buffer_size/2 + 3, buffer_size/2 - 4) == 0; 64 | 65 | 66 | return !res && test1 && test2; 67 | } 68 | 69 | static bool nand_ctrnand_test5(void *ctx) 70 | { 71 | nand_crypto_test_data *data = ctx; 72 | char *buffer = data->buffer; 73 | size_t buffer_size = data->buffer_size; 74 | 75 | uint32_t loc = 0x5A000*0x200; 76 | char text[0x200*8] = "DATA"; 77 | size_t text_size = 5; 78 | 79 | int res = ctr_io_write(&data->io, text, text_size, loc); 80 | res |= ctr_io_read(&data->io, buffer, buffer_size, loc, text_size); 81 | 82 | bool test1 = !memcmp(buffer, text, text_size); 83 | 84 | for (size_t i = 0; i < sizeof(text); ++i) 85 | { 86 | text[i] = i; 87 | } 88 | 89 | loc -= 0x200*4 + 3; 90 | text_size = sizeof(text); 91 | res |= ctr_io_write(&data->io, text, text_size, loc); 92 | res |= ctr_io_read(&data->io, buffer, buffer_size, loc, text_size); 93 | 94 | bool test2 = !memcmp(buffer, text, text_size); 95 | 96 | return !res && test1 && test2; 97 | } 98 | 99 | static bool nand_ctrnand_test6(void *ctx) 100 | { 101 | nand_crypto_test_data *data = ctx; 102 | char *buffer = data->buffer; 103 | size_t buffer_size = data->buffer_size; 104 | 105 | uint32_t loc = 0x5A000; 106 | char text[0x200*8] = { 'D', 'A', 'T', 'A', 0 }; 107 | size_t text_size = 0x200; 108 | 109 | int res = ctr_io_write_sector(&data->io, text, text_size, loc); 110 | 111 | res |= ctr_io_read_sector(&data->io, buffer, buffer_size, loc, 1); 112 | 113 | bool test1 = !memcmp(buffer, text, text_size); 114 | 115 | for (size_t i = 0; i < sizeof(text); ++i) 116 | { 117 | text[i] = i; 118 | } 119 | 120 | loc -= 0x200*4; 121 | text_size = sizeof(text); 122 | 123 | res |= ctr_io_write_sector(&data->io, text, text_size, loc); 124 | 125 | res |= ctr_io_read_sector(&data->io, buffer, buffer_size, loc, text_size/0x200); 126 | 127 | bool test2 = !memcmp(buffer, text, text_size); 128 | 129 | return !res && test1 && test2; 130 | } 131 | 132 | #include 133 | 134 | static bool nand_ctrnand_test7(void *ctx) 135 | { 136 | FILE *file = fopen("CTRNAND:/dbs/certs.db", "rb"); 137 | if (!file) return false; 138 | fclose(file); 139 | 140 | return true; 141 | } 142 | #include "test.h" 143 | 144 | void nand_crypto_tests_initialize(ctr_unit_tests *nand_crypto_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *nand_crypto_ctx) 145 | { 146 | ctr_unit_tests_initialize(nand_crypto_tests, "NAND crypto tests", funcs, 7); 147 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_initialize", nand_crypto_ctx, nand_ctrnand_test1 }); 148 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_read", nand_crypto_ctx, nand_ctrnand_test3 }); 149 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_read_sector", nand_crypto_ctx, nand_ctrnand_test2 }); 150 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_read compare", nand_crypto_ctx, nand_ctrnand_test4 }); 151 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_write", nand_crypto_ctx, nand_ctrnand_test5 }); 152 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_write_sector", nand_crypto_ctx, nand_ctrnand_test6 }); 153 | ctr_unit_tests_add_test(nand_crypto_tests, (ctr_unit_test){ "ctr_nand_crypto_mount_file", nand_crypto_ctx, nand_ctrnand_test7 }); 154 | } 155 | -------------------------------------------------------------------------------- /test/nand_crypto_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_NAND_CRYPTO_TESTS_H_ 2 | #define CTR_NAND_CRYPTO_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | char *buffer; 11 | size_t buffer_size; 12 | ctr_nand_crypto_interface io; 13 | ctr_io_interface *lower_io; 14 | } nand_crypto_test_data; 15 | 16 | nand_crypto_test_data nand_crypto_test_data_initialize(char *buffer, size_t buffer_size, ctr_io_interface *lower_io); 17 | 18 | void nand_crypto_tests_initialize(ctr_unit_tests *nand_crypto_test, ctr_unit_test *funcs, size_t number_of_funcs, void *nand_crypto_ctx); 19 | 20 | #endif//CTR_NAND_CRYPTO_TESTS_H_ 21 | 22 | -------------------------------------------------------------------------------- /test/nand_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_NAND_TESTS_H_ 2 | #define CTR_NAND_TESTS_H_ 3 | 4 | #include 5 | #include "test.h" 6 | 7 | #include 8 | 9 | 10 | typedef struct 11 | { 12 | char *buffer; 13 | size_t buffer_size; 14 | ctr_nand_interface nand_io; 15 | 16 | } nand_test_data; 17 | 18 | void nand_tests_initialize(ctr_unit_tests *nand_test, ctr_unit_test *funcs, size_t number_of_funcs, void *nand_ctx); 19 | 20 | #endif//CTR_NAND_TESTS_H_ 21 | 22 | -------------------------------------------------------------------------------- /test/sd_tests.c: -------------------------------------------------------------------------------- 1 | #include "sd_tests.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static bool sd_test1(void *ctx) 8 | { 9 | sd_test_data *data = ctx; 10 | 11 | int res = ctr_sd_interface_initialize(&data->io); 12 | 13 | return !res; 14 | } 15 | 16 | static bool sd_test2(void *ctx) 17 | { 18 | sd_test_data *data = ctx; 19 | char *buffer = data->buffer; 20 | size_t buffer_size = data->buffer_size; 21 | 22 | uint32_t loc = 0; 23 | int res = ctr_io_read(&data->io, buffer, buffer_size/2, loc, buffer_size/2); 24 | res |= ctr_io_read_sector(&data->io, buffer+buffer_size/2, buffer_size/2, loc /0x200, buffer_size/2/512); 25 | bool test1 = memcmp(buffer, buffer + buffer_size/2, buffer_size/2) == 0; 26 | 27 | res |= ctr_io_read(&data->io, buffer, buffer_size/2, loc+3, buffer_size/2-4); 28 | 29 | bool test2 = memcmp(buffer, buffer + buffer_size/2 + 3, buffer_size/2 - 4) == 0; 30 | 31 | return !res && test1 && test2; 32 | } 33 | 34 | static bool sd_test3(void *ctx) 35 | { 36 | FILE *otp = fopen("SD:/otp.bin", "rb"); 37 | if (otp) 38 | { 39 | struct stat st; 40 | fstat(fileno(otp), &st); 41 | off_t size = st.st_size; 42 | fclose(otp); 43 | return size == 256; 44 | } 45 | return false; 46 | } 47 | 48 | static bool sd_test4(void *ctx) 49 | { 50 | FILE *file = fopen("SD:/test_data.txt", "wrb"); 51 | if (file) 52 | { 53 | const char * string = "HELLO WORLD!!!"; 54 | struct stat st; 55 | fwrite(string, strlen(string), 1, file); 56 | fflush(file); 57 | fstat(fileno(file), &st); 58 | size_t size = (size_t)(st.st_size); 59 | fclose(file); 60 | return size == strlen(string); 61 | } 62 | return false; 63 | 64 | } 65 | 66 | void sd_tests_initialize(ctr_unit_tests *sd_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *sd_ctx) 67 | { 68 | ctr_unit_tests_initialize(sd_tests, "SD tests", funcs, 4); 69 | ctr_unit_tests_add_test(sd_tests, (ctr_unit_test){ "ctr_sd_initialize", sd_ctx, sd_test1}); 70 | ctr_unit_tests_add_test(sd_tests, (ctr_unit_test){ "ctr_sd_read* compare", sd_ctx, sd_test2}); 71 | ctr_unit_tests_add_test(sd_tests, (ctr_unit_test){ "ctr_sd_interface FATFS read", sd_ctx, sd_test3}); 72 | ctr_unit_tests_add_test(sd_tests, (ctr_unit_test){ "ctr_sd_interface FATFS write", sd_ctx, sd_test4}); 73 | } 74 | -------------------------------------------------------------------------------- /test/sd_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_SD_TESTS_H_ 2 | #define CTR_SD_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | char *buffer; 11 | size_t buffer_size; 12 | ctr_sd_interface io; 13 | } sd_test_data; 14 | 15 | void sd_tests_initialize(ctr_unit_tests *sd_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *sd_ctx); 16 | 17 | #endif//CTR_SD_TESTS_H_ 18 | 19 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | #include 5 | 6 | bool ctr_execute_unit_test(ctr_unit_test *test) 7 | { 8 | bool result; 9 | result = test->function(test->data); 10 | if (!result) 11 | { 12 | printf("Executing unit test: %s\n", test->name); 13 | printf(" Result: %s\n", result ? "SUCCESS" : "FAILURE"); 14 | } 15 | return result; 16 | } 17 | 18 | bool ctr_execute_unit_tests(ctr_unit_tests *tests) 19 | { 20 | bool result = true; 21 | printf("Executing test group: %s\n", tests->group_name); 22 | 23 | for (size_t i = 0; i < tests->test_count; ++i) 24 | { 25 | if (!ctr_execute_unit_test(&(tests->test[i])) && result) 26 | { 27 | result = false; 28 | } 29 | } 30 | printf("Done test group: %s\n result: %s\n", tests->group_name, result ? "SUCCESS" : "FAILURE"); 31 | return result; 32 | } 33 | 34 | void ctr_unit_tests_initialize(ctr_unit_tests *tests, const char *name, ctr_unit_test *entry_buffer, size_t max_entry_count) 35 | { 36 | tests->group_name = name; 37 | tests->test = entry_buffer; 38 | tests->test_count = 0; 39 | tests->max_count = max_entry_count; 40 | } 41 | 42 | void ctr_unit_tests_add_test(ctr_unit_tests *tests, ctr_unit_test test) 43 | { 44 | if (tests->test_count < tests->max_count) 45 | tests->test[tests->test_count++] = test; 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR9_UNIT_TEST_H_ 2 | #define CTR9_UNIT_TEST_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef bool (*ctr_unit_test_f)(void* data); 8 | 9 | typedef struct 10 | { 11 | const char* name; 12 | void *data; 13 | ctr_unit_test_f function; 14 | } ctr_unit_test; 15 | 16 | typedef struct 17 | { 18 | const char *group_name; 19 | ctr_unit_test *test; 20 | size_t test_count; 21 | size_t max_count; 22 | } ctr_unit_tests; 23 | 24 | bool ctr_execute_unit_test(ctr_unit_test *test); 25 | 26 | bool ctr_execute_unit_tests(ctr_unit_tests *tests); 27 | 28 | void ctr_unit_tests_initialize(ctr_unit_tests *tests, const char *name, ctr_unit_test *entry_buffer, size_t max_entry_count); 29 | 30 | void ctr_unit_tests_add_test(ctr_unit_tests *tests, ctr_unit_test test); 31 | 32 | #endif//CTR9_UNIT_TEST_H_ 33 | 34 | -------------------------------------------------------------------------------- /test/twl_tests.c: -------------------------------------------------------------------------------- 1 | #include "twl_tests.h" 2 | #include "nand_crypto_tests.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static bool twl_test1(void *ctx) 12 | { 13 | nand_crypto_test_data *data = ctx; 14 | char *buffer = data->buffer; 15 | 16 | ctr_twl_keyslot_setup(); 17 | 18 | int res = ctr_nand_crypto_interface_initialize(&data->io, 0x03, NAND_TWL, data->lower_io); 19 | 20 | return !res; 21 | } 22 | 23 | static bool twl_test2(void *ctx) 24 | { 25 | bool test1 = false, test2 = false; 26 | 27 | FILE *file = fopen("TWLN:/sys/TWLFontTable.dat", "rb"); 28 | if (file) 29 | { 30 | struct stat st; 31 | fstat(fileno(file), &st); 32 | off_t size = st.st_size; 33 | fclose(file); 34 | test1 = size == 863296; 35 | } 36 | 37 | if ((file = fopen("TWLP:/photo/private/ds/app/484E494A/pit.bin", "rb"))) 38 | { 39 | struct stat st; 40 | fstat(fileno(file), &st); 41 | off_t size = st.st_size; 42 | fclose(file); 43 | test2 = size == 8032; 44 | } 45 | return test1 && test2; 46 | } 47 | 48 | static bool twl_test3(void *ctx) 49 | { 50 | bool test1 = false; 51 | FILE *file; 52 | if ((file = fopen("TWLN:/shared2/0000", "r+b"))) 53 | { 54 | ctr_file_interface io; 55 | ctr_file_interface_initialize(&io, file); 56 | 57 | ctr_setup_disk_parameters params = { &io, 0, ctr_io_disk_size(&io)/0x200 }; 58 | disk_ioctl_(4, CTR_SETUP_DISK, ¶ms); 59 | 60 | FILE *file2 = fopen("DISK0:/foobar.txt", "wb"); 61 | printf("Did it open: %d\n", file2 != NULL); 62 | if (file2) 63 | { 64 | size_t written = fwrite("FOOBAR\nhello world!!!", sizeof("FOOBAR\nhello world!!!")-1, 1, file2); 65 | printf("this many elements got written: %zu\n", written); 66 | test1 = written == 1; 67 | fclose(file2); 68 | } 69 | 70 | } 71 | 72 | return test1; 73 | } 74 | 75 | void twl_tests_initialize(ctr_unit_tests *twl_crypto_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *twl_crypto_ctx) 76 | { 77 | ctr_unit_tests_initialize(twl_crypto_tests, "TWL tests", funcs, 3); 78 | ctr_unit_tests_add_test(twl_crypto_tests, (ctr_unit_test){ "twl_crypto_initialize", twl_crypto_ctx, twl_test1 }); 79 | ctr_unit_tests_add_test(twl_crypto_tests, (ctr_unit_test){ "twl mount and read", twl_crypto_ctx, twl_test2 }); 80 | ctr_unit_tests_add_test(twl_crypto_tests, (ctr_unit_test){ "twl mount nested", twl_crypto_ctx, twl_test3 }); 81 | } 82 | -------------------------------------------------------------------------------- /test/twl_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef CTR_TWL_TESTS_H_ 2 | #define CTR_TWL_TESTS_H_ 3 | 4 | #include "test.h" 5 | #include 6 | #include 7 | 8 | void twl_tests_initialize(ctr_unit_tests *twl_tests, ctr_unit_test *funcs, size_t number_of_funcs, void *twl_ctx); 9 | 10 | #endif//CTR_TWL_TESTS_H_ 11 | 12 | --------------------------------------------------------------------------------