├── .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 |
--------------------------------------------------------------------------------