├── icon.bmp ├── template.7z ├── logo ├── logo.png └── logo.xcf ├── arm9 ├── graphics │ ├── subLoad.bmp │ ├── topLoad.bmp │ ├── dsiOnly_bot.bmp │ └── dsiOnly_top.bmp ├── graphics_xcf │ ├── credits.xcf │ └── topSplash.xcf ├── graphics_unused │ ├── subError.bmp │ └── topError.bmp ├── source │ ├── fileOperations.h │ ├── fileOperations.cpp │ ├── lzw.hpp │ ├── bios_decompress_callback.h │ ├── bios_decompress_callback.c │ ├── tonccpy.h │ ├── dsi_only.cpp │ ├── nds_loader_arm9.h │ ├── stringtool.h │ ├── stringtool.cpp │ ├── inifile.h │ ├── gif.hpp │ ├── lzw.cpp │ ├── tonccpy.c │ ├── nds_loader_arm9.c │ ├── gif.cpp │ ├── inifile.cpp │ └── main.cpp ├── ds_arm9_hiya.specs ├── ds_arm9_hiya.mem └── Makefile ├── .gitmodules ├── .gitignore ├── bootloader ├── source │ ├── arm9mpu_reset.s │ ├── bios.s │ ├── boot.h │ ├── card.h │ ├── fat.h │ ├── io_dldi.h │ ├── arm7clear.s │ ├── disc_io.h │ ├── arm9clear.arm.c │ ├── io_dldi.s │ ├── load_crt0.s │ ├── sdmmc.h │ ├── boot.c │ ├── sdmmc.c │ └── fat.c ├── arm9code │ └── mpu_reset.s ├── Makefile └── load.ld ├── hiyaCFW.pnps ├── .gitattributes ├── hiyaCFW.pnproj ├── README.md ├── arm7 ├── source │ └── main.c └── Makefile ├── .github └── workflows │ └── build.yml ├── Makefile ├── hiyacfw_helper.py └── fix_ndsheader.py /icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/icon.bmp -------------------------------------------------------------------------------- /template.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/template.7z -------------------------------------------------------------------------------- /logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/logo/logo.png -------------------------------------------------------------------------------- /logo/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/logo/logo.xcf -------------------------------------------------------------------------------- /arm9/graphics/subLoad.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics/subLoad.bmp -------------------------------------------------------------------------------- /arm9/graphics/topLoad.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics/topLoad.bmp -------------------------------------------------------------------------------- /arm9/graphics/dsiOnly_bot.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics/dsiOnly_bot.bmp -------------------------------------------------------------------------------- /arm9/graphics/dsiOnly_top.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics/dsiOnly_top.bmp -------------------------------------------------------------------------------- /arm9/graphics_xcf/credits.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics_xcf/credits.xcf -------------------------------------------------------------------------------- /arm9/graphics_xcf/topSplash.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics_xcf/topSplash.xcf -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/libslim"] 2 | path = libs/libslim 3 | url = https://github.com/DS-Homebrew/libslim.git 4 | -------------------------------------------------------------------------------- /arm9/graphics_unused/subError.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics_unused/subError.bmp -------------------------------------------------------------------------------- /arm9/graphics_unused/topError.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DS-Homebrew/hiyaCFW/HEAD/arm9/graphics_unused/topError.bmp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */build 2 | *.nds 3 | *.dsi 4 | *.cia 5 | *.elf 6 | data/* 7 | *.DS_Store 8 | .vscode 9 | arm9/include/version.h 10 | -------------------------------------------------------------------------------- /bootloader/source/arm9mpu_reset.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .global mpu_reset, mpu_reset_end 3 | 4 | mpu_reset: 5 | .incbin "mpu_reset.bin" 6 | mpu_reset_end: 7 | -------------------------------------------------------------------------------- /arm9/source/fileOperations.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef FILE_COPY 4 | #define FILE_COPY 5 | 6 | extern off_t getFileSize(const char *fileName); 7 | 8 | #endif // FILE_COPY -------------------------------------------------------------------------------- /arm9/ds_arm9_hiya.specs: -------------------------------------------------------------------------------- 1 | %rename link old_link 2 | 3 | *link: 4 | %(old_link) -T ../ds_arm9_hiya.mem%s -T ds_arm9.ld%s --gc-sections 5 | 6 | *startfile: 7 | ds_arm9_crt0%O%s crti%O%s crtbegin%O%s 8 | 9 | -------------------------------------------------------------------------------- /hiyaCFW.pnps: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bootloader/source/bios.s: -------------------------------------------------------------------------------- 1 | .text 2 | .align 4 3 | 4 | .thumb 5 | 6 | @--------------------------------------------------------------------------------- 7 | .global swiDelay 8 | .thumb_func 9 | @--------------------------------------------------------------------------------- 10 | swiDelay: 11 | @--------------------------------------------------------------------------------- 12 | swi 0x03 13 | bx lr 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /arm9/source/fileOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "fileOperations.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | off_t getFileSize(const char *fileName) 11 | { 12 | FILE* fp = fopen(fileName, "rb"); 13 | off_t fsize = 0; 14 | if (fp) { 15 | fseek(fp, 0, SEEK_END); 16 | fsize = ftell(fp); // Get source file's size 17 | fseek(fp, 0, SEEK_SET); 18 | fclose(fp); 19 | } 20 | 21 | return fsize; 22 | } 23 | -------------------------------------------------------------------------------- /bootloader/source/boot.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOOT_H_ 2 | #define _BOOT_H_ 3 | 4 | #define initMBK_ARM9_size 0x400 5 | void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) initMBK_ARM9 (); 6 | #define resetMemory2_ARM9_size 0x400 7 | void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9(); 8 | #define startBinary_ARM9_size 0x100 9 | void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) startBinary_ARM9 (); 10 | #define ARM9_START_FLAG (*(vu8*)0x02FFFDFB) 11 | 12 | #endif // _BOOT_H_ 13 | -------------------------------------------------------------------------------- /arm9/ds_arm9_hiya.mem: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | This Source Code Form is subject to the terms of the Mozilla Public License, 3 | v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | obtain one at https://mozilla.org/MPL/2.0/. 5 | --------------------------------------------------------------------------------*/ 6 | MEMORY { 7 | ewram : ORIGIN = 0x02004000, LENGTH = 3M + 512K - 0x4000 8 | dtcm : ORIGIN = 0x0b000000, LENGTH = 16K 9 | vectors : ORIGIN = 0x01000000, LENGTH = 256 10 | itcm : ORIGIN = 0x01000100, LENGTH = 32K - 256 11 | } 12 | -------------------------------------------------------------------------------- /hiyaCFW.pnproj: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /arm9/source/lzw.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LZW_HPP 2 | #define LZW_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef unsigned int uint; 9 | typedef std::vector::const_iterator u8_itr; 10 | 11 | class LZWReader { 12 | constexpr static u16 MAX_WIDTH = 12; 13 | constexpr static u16 DECODER_INVALID_CODE = 0xFFFF; 14 | constexpr static u16 FLUSH_BUFFER = 1 << MAX_WIDTH; 15 | 16 | int litWidth; 17 | std::function flushFn; 18 | u32 bits = 0; 19 | uint nBits = 0; 20 | uint width; 21 | bool err = false; 22 | 23 | u16 clear, eof, hi, overflow, last; 24 | 25 | std::vector suffix; 26 | std::vector prefix; 27 | 28 | std::vector output; 29 | int o = 0; 30 | // std::vector toRead; 31 | 32 | u16 readLSB(std::vector::iterator &it, const std::vector::iterator &end); 33 | 34 | int read(std::vector &buffer); 35 | 36 | void flush(void); 37 | 38 | public: 39 | LZWReader(int minCodeSize, std::function flushFunction); 40 | 41 | bool decode(std::vector::iterator begin, std::vector::iterator end); 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /arm9/source/bios_decompress_callback.h: -------------------------------------------------------------------------------- 1 | /* 2 | NitroHax -- Cheat tool for the Nintendo DS 3 | Copyright (C) 2008 Michael "Chishm" Chisholm 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef BIOS_DECOMPRESS_CALLBACK_H 20 | #define BIOS_DECOMPRESS_CALLBACK_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include 27 | #include 28 | 29 | extern TDecompressionStream decompressBiosCallback; 30 | 31 | 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif // BIOS_DECOMPRESS_CALLBACK_H 38 | 39 | -------------------------------------------------------------------------------- /arm9/source/bios_decompress_callback.c: -------------------------------------------------------------------------------- 1 | /* 2 | NitroHax -- Cheat tool for the Nintendo DS 3 | Copyright (C) 2008 Michael "Chishm" Chisholm 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "bios_decompress_callback.h" 20 | 21 | static int getSizeBiosCallback (uint8 * source, uint16 * dest, uint32 r2) 22 | { 23 | (void)dest; 24 | (void)r2; 25 | return *((int*)source); 26 | } 27 | 28 | static uint8 readByteBiosCallback (uint8 * source) 29 | { 30 | return *source; 31 | } 32 | 33 | TDecompressionStream decompressBiosCallback = 34 | { 35 | getSizeBiosCallback, 36 | (void*)0, 37 | readByteBiosCallback 38 | } ; 39 | 40 | 41 | -------------------------------------------------------------------------------- /arm9/source/tonccpy.h: -------------------------------------------------------------------------------- 1 | //# Stuff you may not have yet. 2 | 3 | #ifndef TONCCPY_H 4 | #define TONCCPY_H 5 | 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | 13 | typedef unsigned int uint; 14 | #define BIT_MASK(len) ( (1<<(len))-1 ) 15 | static inline u32 quad8(u8 x) { x |= x<<8; return x | x<<16; } 16 | 17 | 18 | //# Declarations and inlines. 19 | 20 | void tonccpy(void *dst, const void *src, uint size); 21 | 22 | void __toncset(void *dst, u32 fill, uint size); 23 | static inline void toncset(void *dst, u8 src, uint size); 24 | static inline void toncset16(void *dst, u16 src, uint size); 25 | static inline void toncset32(void *dst, u32 src, uint size); 26 | 27 | 28 | //! VRAM-safe memset, byte version. Size in bytes. 29 | static inline void toncset(void *dst, u8 src, uint size) 30 | { __toncset(dst, quad8(src), size); } 31 | 32 | //! VRAM-safe memset, halfword version. Size in hwords. 33 | static inline void toncset16(void *dst, u16 src, uint size) 34 | { __toncset(dst, src|src<<16, size*2); } 35 | 36 | //! VRAM-safe memset, word version. Size in words. 37 | static inline void toncset32(void *dst, u32 src, uint size) 38 | { __toncset(dst, src, size*4); } 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | #endif 44 | -------------------------------------------------------------------------------- /arm9/source/dsi_only.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dsiOnly_top.h" 3 | #include "dsiOnly_bot.h" 4 | 5 | static void dsiOnly_setBrightness(u8 screen, s8 bright) { 6 | u16 mode = 1 << 14; 7 | 8 | if (bright < 0) { 9 | mode = 2 << 14; 10 | bright = -bright; 11 | } 12 | if (bright > 31) { 13 | bright = 31; 14 | } 15 | *(vu16*)(0x0400006C + (0x1000 * screen)) = bright + mode; 16 | } 17 | 18 | void dsiOnly(void) { 19 | if (isDSiMode()) return; // Proceed running on DSi 20 | 21 | dsiOnly_setBrightness(0, 31); 22 | dsiOnly_setBrightness(1, 31); 23 | 24 | videoSetMode(MODE_4_2D); 25 | videoSetModeSub(MODE_4_2D); 26 | 27 | vramSetBankA(VRAM_A_MAIN_BG); 28 | vramSetBankB(VRAM_B_MAIN_BG); 29 | vramSetBankC(VRAM_C_SUB_BG); 30 | vramSetBankD(VRAM_D_LCD); 31 | 32 | // Display DSi Only screen 33 | int bg3 = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0); 34 | decompress(dsiOnly_topBitmap, bgGetGfxPtr(bg3), LZ77Vram); 35 | for (int i = 0; i < 16; i++) { 36 | BG_PALETTE[i] = dsiOnly_topPal[i]; 37 | } 38 | 39 | int bg3sub = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0); 40 | decompress(dsiOnly_botBitmap, bgGetGfxPtr(bg3sub), LZ77Vram); 41 | for (int i = 0; i < 16; i++) { 42 | BG_PALETTE_SUB[i] = dsiOnly_botPal[i]; 43 | } 44 | 45 | dsiOnly_setBrightness(0, 0); 46 | dsiOnly_setBrightness(1, 0); 47 | 48 | while (1) { 49 | swiWaitForVBlank(); 50 | } 51 | } -------------------------------------------------------------------------------- /arm9/source/nds_loader_arm9.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | Copyright (C) 2005 - 2010 3 | Michael "Chishm" Chisholm 4 | Dave "WinterMute" Murphy 5 | 6 | This program is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU General Public License 8 | as published by the Free Software Foundation; either version 2 9 | of the License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | 20 | ------------------------------------------------------------------*/ 21 | 22 | #ifndef NDS_LOADER_ARM9_H 23 | #define NDS_LOADER_ARM9_H 24 | 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #define LOAD_DEFAULT_NDS 0 31 | 32 | int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, int argc, const char** argv); 33 | 34 | int runNdsFile (const char* filename, int argc, const char** argv); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif // NDS_LOADER_ARM7_H 41 | -------------------------------------------------------------------------------- /arm9/source/stringtool.h: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------- 2 | 3 | 4 | Copyright (C) 2007 Acekard, www.acekard.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | 25 | ---------------------------------------------------------------------------------*/ 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | #ifndef _STRINGTOOL_H_ 36 | #define _STRINGTOOL_H_ 37 | 38 | #include 39 | 40 | std::string formatString( const char* fmt, ... ); 41 | 42 | 43 | 44 | #endif//_STRINGTOOL_H_ 45 | -------------------------------------------------------------------------------- /bootloader/source/card.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | 3 | Copyright (C) 2005 Michael "Chishm" Chisholm 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | If you use this code, please give due credit and email me about your 20 | project at chishm@hotmail.com 21 | ------------------------------------------------------------------*/ 22 | 23 | #ifndef CARD_H 24 | #define CARD_H 25 | 26 | #include "disc_io.h" 27 | #include "io_dldi.h" 28 | 29 | static inline bool CARD_StartUp (void) { 30 | return _io_dldi.fn_startup(); 31 | } 32 | 33 | static inline bool CARD_IsInserted (void) { 34 | return _io_dldi.fn_isInserted(); 35 | } 36 | 37 | static inline bool CARD_ReadSector (u32 sector, void *buffer) { 38 | return _io_dldi.fn_readSectors(sector, 1, buffer); 39 | } 40 | 41 | static inline bool CARD_ReadSectors (u32 sector, int count, void *buffer) { 42 | return _io_dldi.fn_readSectors(sector, count, buffer); 43 | } 44 | 45 | #endif // CARD_H 46 | -------------------------------------------------------------------------------- /bootloader/source/fat.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | fat.h 3 | 4 | NDS MP 5 | GBAMP NDS Firmware Hack Version 2.12 6 | An NDS aware firmware patch for the GBA Movie Player. 7 | By Michael Chisholm (Chishm) 8 | 9 | Filesystem code based on GBAMP_CF.c by Chishm (me). 10 | 11 | License: 12 | Copyright (C) 2005 Michael "Chishm" Chisholm 13 | 14 | This program is free software; you can redistribute it and/or 15 | modify it under the terms of the GNU General Public License 16 | as published by the Free Software Foundation; either version 2 17 | of the License, or (at your option) any later version. 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program; if not, write to the Free Software 26 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 27 | 28 | If you use this code, please give due credit and email me about your 29 | project at chishm@hotmail.com 30 | ------------------------------------------------------------------*/ 31 | 32 | #ifndef FAT_H 33 | #define FAT_H 34 | 35 | #include 36 | 37 | #define CLUSTER_FREE 0x00000000 38 | #define CLUSTER_EOF 0x0FFFFFFF 39 | #define CLUSTER_FIRST 0x00000002 40 | 41 | bool FAT_InitFiles (bool initCard); 42 | u32 getBootFileCluster (const char* bootName); 43 | u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length); 44 | u32 FAT_ClustToSect (u32 cluster); 45 | 46 | #endif // FAT_H 47 | -------------------------------------------------------------------------------- /arm9/source/stringtool.cpp: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------- 2 | 3 | 4 | Copyright (C) 2007 Acekard, www.acekard.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | 25 | ---------------------------------------------------------------------------------*/ 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | #include "stringtool.h" 36 | #include 37 | #include 38 | #include 39 | 40 | std::string formatString( const char* fmt, ... ) 41 | { 42 | const char * f = fmt; 43 | va_list argList; 44 | va_start(argList, fmt); 45 | char * ptempStr = NULL; 46 | size_t max_len = vasiprintf( &ptempStr, f, argList); 47 | std::string str( ptempStr ); 48 | str.resize( max_len ); 49 | free( ptempStr ); 50 | va_end(argList); 51 | return str; 52 | } 53 | -------------------------------------------------------------------------------- /bootloader/source/io_dldi.h: -------------------------------------------------------------------------------- 1 | /* 2 | io_dldi.h 3 | 4 | Reserved space for post-compilation adding of an extra driver 5 | 6 | Copyright (c) 2006 Michael "Chishm" Chisholm 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 3. The name of the author may not be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 21 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | 2006-12-22 - Chishm 30 | * Original release 31 | */ 32 | 33 | #ifndef IO_DLDI_H 34 | #define IO_DLDI_H 35 | 36 | // 'DLDD' 37 | #define DEVICE_TYPE_DLDD 0x49444C44 38 | 39 | #include "disc_io.h" 40 | 41 | // export interface 42 | extern IO_INTERFACE _io_dldi ; 43 | 44 | #endif // define IO_DLDI_H 45 | -------------------------------------------------------------------------------- /bootloader/source/arm7clear.s: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | 3 | Copyright (C) 2005 Michael "Chishm" Chisholm 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | If you use this code, please give due credit and email me about your 20 | project at chishm@hotmail.com 21 | ------------------------------------------------------------------*/ 22 | 23 | .arm 24 | .global arm7clearRAM 25 | .type arm7clearRAM STT_FUNC 26 | arm7clearRAM: 27 | 28 | push {r0-r9} 29 | // clear exclusive IWRAM 30 | // 0380:0000 to 0380:FFFF, total 64KiB 31 | mov r0, #0 32 | mov r1, #0 33 | mov r2, #0 34 | mov r3, #0 35 | mov r4, #0 36 | mov r5, #0 37 | mov r6, #0 38 | mov r7, #0 39 | mov r8, #0x03800000 40 | sub r8, #0x00008000 41 | mov r9, #0x03800000 42 | orr r9, r9, #0x10000 43 | clear_IWRAM_loop: 44 | stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7} 45 | cmp r8, r9 46 | blt clear_IWRAM_loop 47 | 48 | // clear most of EWRAM - except after RAM end - 0xc000, which has the bootstub 49 | mov r8, #0x02000000 50 | add r8, #0x00000800 51 | 52 | ldr r9,=0x4004008 53 | ldr r9,[r9] 54 | ands r9,r9,#0x8000 55 | bne dsi_mode 56 | 57 | mov r9, #0x02400000 58 | b ds_mode 59 | dsi_mode: 60 | mov r9, #0x03000000 61 | ds_mode: 62 | sub r9, #0x0000c000 63 | clear_EWRAM_loop: 64 | stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7} 65 | cmp r8, r9 66 | blt clear_EWRAM_loop 67 | 68 | pop {r0-r9} 69 | 70 | bx lr 71 | 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | 4 | GBAtemp Thread 5 | 6 | 7 | Discord Server 8 | 9 | 10 | Build status on GitHub Actions 11 | 12 |

13 | 14 | HiyaCFW is the world's FIRST Nintendo DSi CFW, made by the talented folks over on our Discord server. 15 | 16 | # Features 17 | 18 | - Run custom DSiWare 19 | - NAND to SD card redirection 20 | - Run NAND backups from any console 21 | - Replace the system menu with **TW**i**L**ight Menu++ 22 | - Run blocked flashcards (such as R4 Ultra) 23 | - Remove region-locking 24 | - Change the NAND region (Not compatible with CHN and KOR NANDs) 25 | - Run 3DS-exclusive DSiWare (such as WarioWare Touched) 26 | - Custom splash screens 27 | 28 | # Compiling 29 | 30 | In order to compile this on your own, you will need [devkitPro](https://devkitpro.org/)'s toolchains with the devkitARM, plus the necessary tools and libraries. `dkp-pacman` is included for easy installation of all components: 31 | 32 | ``` 33 | $ dkp-pacman -Syu devkitARM general-tools dstools ndstool libnds 34 | ``` 35 | 36 | Once everything is downloaded and installed, `git clone` this repository, navigate to the folder, and run `make` to compile HiyaCFW. If there is an error, let us know. 37 | 38 | # Credits 39 | - Apache Thunder, NoCash, StuckPixel, Shutterbug2000, and Gericom. 40 | - Drenn: .bmp loading code from GameYob, for custom splash screens. 41 | - Pk11: .gif loading code for animated splash screens. 42 | - Rocket Robz: Logo graphic, settings screen, support for region-changing and any NAND backup. 43 | - devkitPro: For the majority of the base code like nds-bootloader which this loader uses. 44 | -------------------------------------------------------------------------------- /arm7/source/main.c: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------- 2 | 3 | default ARM7 core 4 | 5 | Copyright (C) 2005 - 2010 6 | Michael Noland (joat) 7 | Jason Rogers (dovoto) 8 | Dave Murphy (WinterMute) 9 | 10 | This software is provided 'as-is', without any express or implied 11 | warranty. In no event will the authors be held liable for any 12 | damages arising from the use of this software. 13 | 14 | Permission is granted to anyone to use this software for any 15 | purpose, including commercial applications, and to alter it and 16 | redistribute it freely, subject to the following restrictions: 17 | 18 | 1. The origin of this software must not be misrepresented; you 19 | must not claim that you wrote the original software. If you use 20 | this software in a product, an acknowledgment in the product 21 | documentation would be appreciated but is not required. 22 | 23 | 2. Altered source versions must be plainly marked as such, and 24 | must not be misrepresented as being the original software. 25 | 26 | 3. This notice may not be removed or altered from any source 27 | distribution. 28 | 29 | ---------------------------------------------------------------------------------*/ 30 | #include 31 | 32 | #define SD_IRQ_STATUS (*(vu32*)0x400481C) 33 | 34 | void VcountHandler() { inputGetAndSend(); } 35 | 36 | int main(void) { 37 | 38 | irqInit(); 39 | 40 | readUserSettings(); 41 | 42 | initClockIRQ(); 43 | 44 | fifoInit(); 45 | 46 | SetYtrigger(80); 47 | 48 | installSystemFIFO(); 49 | 50 | fifoSendValue32(FIFO_USER_01, SD_IRQ_STATUS); 51 | fifoSendValue32(FIFO_USER_02, i2cReadRegister(0x4A, 0x70)); 52 | 53 | irqSet(IRQ_VCOUNT, VcountHandler); 54 | 55 | irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK ); 56 | 57 | while (1) { 58 | /* if (*(u32*)0x02FFFD0C == 0x54534453) { // 'SDST' 59 | fifoSendValue32(FIFO_USER_01, SD_IRQ_STATUS); 60 | *(u32*)0x02FFFD0C = 0; 61 | } */ 62 | if(fifoCheckValue32(FIFO_USER_04)) { 63 | if(fifoCheckValue32(FIFO_USER_03)) { 64 | i2cWriteRegister(0x4A, 0x70, 0x01); // Bootflag = Warmboot/SkipHealthSafety 65 | } 66 | // After writing i2c, set FIFO_USER_04 back to 0 so arm7 doesn't repeatedly run i2c code. 67 | fifoSendValue32(FIFO_USER_04, 0); 68 | } 69 | swiWaitForVBlank(); 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /arm9/source/inifile.h: -------------------------------------------------------------------------------- 1 | /* 2 | inifile.h 3 | Copyright (C) 2007 Acekard, www.acekard.com 4 | Copyright (C) 2007-2009 somebody 5 | Copyright (C) 2009-2010 yellow wood goblin 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #ifndef _INIFILE_H_ 22 | #define _INIFILE_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | class CIniFile 29 | { 30 | public: 31 | CIniFile(); 32 | CIniFile(const std::string& filename); 33 | virtual ~CIniFile(); 34 | 35 | public: 36 | bool LoadIniFile(const std::string& FileName); 37 | bool SaveIniFile(const std::string& FileName); 38 | bool SaveIniFileModified(const std::string& FileName); 39 | 40 | std::string GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue); 41 | void SetString(const std::string& Section,const std::string& Item,const std::string& Value); 42 | int GetInt(const std::string& Section,const std::string& Item,int DefaultValue); 43 | void SetInt(const std::string& Section,const std::string& Item,int Value); 44 | void GetStringVector(const std::string& Section,const std::string& Item,std::vector& strings,char delimiter=','); 45 | void SetStringVector(const std::string& Section,const std::string& Item,std::vector& strings,char delimiter=','); 46 | protected: 47 | std::string m_sFileName; 48 | typedef std::vector cStringArray; 49 | cStringArray m_FileContainer; 50 | bool m_bLastResult; 51 | bool m_bModified; 52 | bool m_bReadOnly; 53 | typedef std::map cSectionCache; 54 | cSectionCache m_Cache; 55 | 56 | bool InsertLine(size_t line,const std::string& str); 57 | bool ReplaceLine(size_t line,const std::string& str); 58 | 59 | void SetFileString(const std::string& Section,const std::string& Item,const std::string& Value); 60 | std::string GetFileString(const std::string& Section,const std::string& Item); 61 | 62 | std::string GetString(const std::string& Section,const std::string& Item); 63 | int GetInt(const std::string& Section,const std::string& Item); 64 | }; 65 | 66 | #endif // _INIFILE_H_ 67 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build hiyaCFW 2 | 3 | on: 4 | push: 5 | branches: ["*"] 6 | paths-ignore: 7 | - 'README.md' 8 | pull_request: 9 | branches: ["*"] 10 | paths-ignore: 11 | - 'README.md' 12 | release: 13 | types: [created] 14 | workflow_dispatch: 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | container: devkitpro/devkitarm:20241104 20 | name: Build with Docker using devkitARM 21 | steps: 22 | - name: Checkout repo 23 | uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | - name: Install tools 27 | run: | 28 | sudo apt-get update 29 | sudo apt-get install p7zip-full python -y 30 | - name: Silence all git safe directory warnings 31 | run: | 32 | git config --system --add safe.directory '*' 33 | git fetch --prune --unshallow --tags 34 | - name: Build 35 | id: build 36 | run: | 37 | make 38 | - name: Pack 7z for nightly 39 | if: ${{ !startsWith(github.ref, 'refs/tags') }} 40 | run: | 41 | mkdir hiyaCFW 42 | cp hiya.dsi hiyaCFW 43 | 7z a hiyaCFW.7z hiyaCFW 44 | - name: Pack 7z for release 45 | if: ${{ startsWith(github.ref, 'refs/tags') }} 46 | run: | 47 | mkdir "for SDNAND SD card" 48 | cp hiya.dsi "for SDNAND SD card" 49 | 7z a template.7z "for SDNAND SD card" 50 | mv template.7z hiyaCFW.7z 51 | - name: Publish build to GH Actions 52 | uses: actions/upload-artifact@main 53 | with: 54 | path: hiyaCFW.7z 55 | name: build 56 | 57 | # Only run this for non-PR jobs. 58 | publish_build: 59 | runs-on: ubuntu-latest 60 | name: Publish build to release 61 | if: ${{ success() && !startsWith(github.ref, 'refs/pull') }} 62 | needs: build 63 | steps: 64 | - name: Download artifacts 65 | uses: actions/download-artifact@main 66 | with: 67 | name: build 68 | path: build 69 | - name: Upload to ${{ github.repository }} release 70 | if: ${{ startsWith(github.ref, 'refs/tags') }} 71 | run: | 72 | ID=$(jq --raw-output '.release.id' $GITHUB_EVENT_PATH) 73 | 74 | for file in ${{ github.workspace }}/build/*; do 75 | AUTH_HEADER="Authorization: token ${{ secrets.GITHUB_TOKEN }}" 76 | CONTENT_LENGTH="Content-Length: $(stat -c%s $file)" 77 | CONTENT_TYPE="Content-Type: application/7z-x-compressed" 78 | UPLOAD_URL="https://uploads.github.com/repos/${{ github.repository }}/releases/$ID/assets?name=$(basename $file)" 79 | 80 | curl -XPOST -H "$AUTH_HEADER" -H "$CONTENT_LENGTH" -H "$CONTENT_TYPE" --upload-file "$file" "$UPLOAD_URL" 81 | done 82 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | .SECONDARY: 5 | 6 | ifeq ($(strip $(DEVKITARM)),) 7 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 8 | endif 9 | 10 | ifneq (,$(shell which python3)) 11 | PYTHON := python3 12 | else ifneq (,$(shell which python2)) 13 | PYTHON := python2 14 | else ifneq (,$(shell which python)) 15 | PYTHON := python 16 | else 17 | $(error "Python not found in PATH, please install it.") 18 | endif 19 | 20 | export TARGET := $(shell basename $(CURDIR)) 21 | export TOPDIR := $(CURDIR) 22 | 23 | # specify a directory which contains the nitro filesystem 24 | # this is relative to the Makefile 25 | NITRO_FILES := 26 | 27 | # These set the information text in the nds file 28 | GAME_ICON := icon.bmp 29 | GAME_TITLE := hiyaCFW 30 | GAME_SUBTITLE1 := CFW for Nintendo DSi 31 | GAME_SUBTITLE2 := made by Apache Thunder 32 | 33 | include $(DEVKITARM)/ds_rules 34 | 35 | .PHONY: bootloader checkarm7 checkarm9 clean libslim 36 | 37 | #--------------------------------------------------------------------------------- 38 | # main targets 39 | #--------------------------------------------------------------------------------- 40 | all: libslim bootloader checkarm7 checkarm9 $(TARGET).nds 41 | 42 | #--------------------------------------------------------------------------------- 43 | bootloader: 44 | $(MAKE) -C bootloader "EXTRA_CFLAGS= -DNO_DLDI" 45 | 46 | #--------------------------------------------------------------------------------- 47 | checkarm7: 48 | $(MAKE) -C arm7 49 | 50 | #--------------------------------------------------------------------------------- 51 | checkarm9: 52 | $(MAKE) -C arm9 53 | 54 | #--------------------------------------------------------------------------------- 55 | $(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf 56 | ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf -r9 00080002 \ 57 | -b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \ 58 | -g HIYA 01 "HIYACFW" -z 80040000 -u 00030004 $(_ADDFILES) 59 | $(PYTHON) fix_ndsheader.py $(TARGET).nds 60 | cp $(TARGET).nds hiya.dsi 61 | 62 | #--------------------------------------------------------------------------------- 63 | arm7/$(TARGET).elf: 64 | $(MAKE) -C arm7 65 | 66 | #--------------------------------------------------------------------------------- 67 | arm9/$(TARGET).elf: 68 | $(MAKE) -C arm9 69 | 70 | #--------------------------------------------------------------------------------- 71 | clean: 72 | @echo clean ... 73 | @$(MAKE) -C arm9 clean 74 | @$(MAKE) -C arm7 clean 75 | @$(MAKE) -C bootloader clean 76 | @$(MAKE) -C libs/libslim clean 77 | @rm -f $(TARGET).nds $(TARGET).nds.orig.nds hiya.dsi 78 | 79 | libslim: 80 | $(MAKE) -C libs/libslim/libslim 81 | -------------------------------------------------------------------------------- /arm9/source/gif.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GIF_HPP 2 | #define GIF_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef unsigned int uint; 9 | 10 | class Gif { 11 | struct Header { 12 | char signature[6]; 13 | u16 width; 14 | u16 height; 15 | u8 gctSize: 3; 16 | u8 sortFlag: 1; 17 | u8 colorResolution: 3; 18 | u8 gctFlag: 1; 19 | u8 bgColor; 20 | u8 pixelAspectRatio; 21 | } __attribute__ ((__packed__)) header; 22 | static_assert(sizeof(Header) == 13); 23 | 24 | struct Frame { 25 | struct GraphicsControlExtension { 26 | u8 transparentColorFlag: 1; 27 | u8 userInputFlag: 1; 28 | u8 disposalMethod: 3; 29 | u8 reserved: 3; 30 | u16 delay; // In hundreths (1/100) of a second 31 | u8 transparentColor; 32 | } __attribute__ ((__packed__)) gce; 33 | static_assert(sizeof(GraphicsControlExtension) == 4); 34 | 35 | // Unsupported for now 36 | // struct PlainText { 37 | // u16 gridX; 38 | // u16 gridY; 39 | // u16 gridW; 40 | // u16 gridH; 41 | // u8 charW; 42 | // u8 charH; 43 | // u8 forgroundIndex; 44 | // u8 backgroundIndex; 45 | // } __attribute__ ((__packed__)) textDescriptor; 46 | // static_assert(sizeof(PlainText) == 12); 47 | 48 | struct Descriptor { 49 | u16 x; 50 | u16 y; 51 | u16 w; 52 | u16 h; 53 | u8 lctSize: 3; 54 | u8 reserved: 2; 55 | u8 sortFlag: 1; 56 | u8 interlaceFlag: 1; 57 | u8 lctFlag: 1; 58 | } __attribute__ ((__packed__)) descriptor; 59 | static_assert(sizeof(Descriptor) == 9); 60 | 61 | struct Image { 62 | u8 lzwMinimumCodeSize; 63 | std::vector imageData; 64 | } image; 65 | 66 | std::vector lct; // In DS format 67 | // std::string text; 68 | bool hasGCE = false; 69 | // bool hasText = false; 70 | bool hasImage = false; 71 | }; 72 | 73 | std::vector _frames; 74 | std::vector _gct; // In DS format 75 | u16 _loopCount = 0xFFFF; 76 | bool _top = false; 77 | bool _compressed = false; 78 | 79 | // Animation vairables 80 | static std::vector _animating; 81 | uint _currentFrame = 0; 82 | uint _currentDelay = 0; 83 | uint _currentDelayProgress = 0; 84 | u16 _currentLoop = 0; 85 | bool _paused = true; 86 | bool _finished = true; 87 | 88 | bool _waitingForInput = false; 89 | 90 | static void animate(bool top); 91 | 92 | void displayFrame(void); 93 | 94 | public: 95 | static void timerHandler(void); 96 | 97 | Gif() {} 98 | Gif(const char *path, bool top, bool animate, bool forceDecompress) { load(path, top, animate, forceDecompress); } 99 | ~Gif() {} 100 | 101 | bool load(const char *path, bool top, bool animate, bool forceDecompress); 102 | 103 | Frame &frame(int frame) { return _frames[frame]; } 104 | std::vector gct() { return _gct; } 105 | 106 | bool paused() { return _paused; } 107 | void pause() { _paused = true; } 108 | void unpause() { _paused = false; } 109 | void toggle() { _paused = !_paused; } 110 | 111 | bool loopForever(void) { return _loopCount == 0xFFFF; } 112 | bool waitingForInput(void) { return _waitingForInput; } 113 | void resume(void) { _waitingForInput = false; _currentDelayProgress = _currentDelay; } 114 | bool finished(void) { return _finished; } 115 | 116 | int currentFrame(void) { return _currentFrame; } 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /bootloader/source/disc_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | disc_io.h 3 | Interface template for low level disc functions. 4 | 5 | Copyright (c) 2006 Michael "Chishm" Chisholm 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation and/or 14 | other materials provided with the distribution. 15 | 3. The name of the author may not be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | 2006-07-11 - Chishm 29 | * Original release 30 | 31 | 2006-07-16 - Chishm 32 | * Renamed _CF_USE_DMA to _IO_USE_DMA 33 | * Renamed _CF_ALLOW_UNALIGNED to _IO_ALLOW_UNALIGNED 34 | */ 35 | 36 | #ifndef _DISC_IO_H 37 | #define _DISC_IO_H 38 | 39 | #include 40 | #define BYTES_PER_SECTOR 512 41 | 42 | //---------------------------------------------------------------------- 43 | // Customisable features 44 | 45 | // Use DMA to read the card, remove this line to use normal reads/writes 46 | // #define _IO_USE_DMA 47 | 48 | // Allow buffers not alligned to 16 bits when reading files. 49 | // Note that this will slow down access speed, so only use if you have to. 50 | // It is also incompatible with DMA 51 | #define _IO_ALLOW_UNALIGNED 52 | 53 | #if defined _IO_USE_DMA && defined _IO_ALLOW_UNALIGNED 54 | #error "You can't use both DMA and unaligned memory" 55 | #endif 56 | 57 | #define FEATURE_MEDIUM_CANREAD 0x00000001 58 | #define FEATURE_MEDIUM_CANWRITE 0x00000002 59 | #define FEATURE_SLOT_GBA 0x00000010 60 | #define FEATURE_SLOT_NDS 0x00000020 61 | 62 | typedef bool (* FN_MEDIUM_STARTUP)(void) ; 63 | typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; 64 | typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u32 numSectors, void* buffer) ; 65 | typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u32 numSectors, const void* buffer) ; 66 | typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; 67 | typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; 68 | 69 | struct IO_INTERFACE_STRUCT { 70 | unsigned long ioType ; 71 | unsigned long features ; 72 | FN_MEDIUM_STARTUP fn_startup ; 73 | FN_MEDIUM_ISINSERTED fn_isInserted ; 74 | FN_MEDIUM_READSECTORS fn_readSectors ; 75 | FN_MEDIUM_WRITESECTORS fn_writeSectors ; 76 | FN_MEDIUM_CLEARSTATUS fn_clearStatus ; 77 | FN_MEDIUM_SHUTDOWN fn_shutdown ; 78 | } ; 79 | 80 | typedef struct IO_INTERFACE_STRUCT IO_INTERFACE ; 81 | 82 | #endif // define _DISC_IO_H 83 | -------------------------------------------------------------------------------- /arm9/source/lzw.cpp: -------------------------------------------------------------------------------- 1 | #include "lzw.hpp" 2 | 3 | u16 LZWReader::readLSB(std::vector::iterator &begin, const std::vector::iterator &end) { 4 | while (nBits < width) { 5 | if (begin == end) { 6 | err = true; 7 | return 0; 8 | } 9 | u8 x = *(begin++); 10 | bits |= x << nBits; 11 | nBits += 8; 12 | } 13 | u16 code = bits & ((1 << width) - 1); 14 | bits >>= width; 15 | nBits -= width; 16 | return code; 17 | } 18 | 19 | bool LZWReader::decode(std::vector::iterator begin, std::vector::iterator end) { 20 | o = 0; 21 | err = false; 22 | // Loop over the code stream, converting codes into decompressed bytes. 23 | while (begin != end) { 24 | u16 code = readLSB(begin, end); 25 | if (err) { 26 | flush(); 27 | return false; 28 | } 29 | 30 | if (code < clear) { // Literal 31 | output[o++] = code; 32 | if (last != DECODER_INVALID_CODE) { 33 | // Save what the hi code expands to. 34 | suffix[hi] = code; 35 | prefix[hi] = last; 36 | } 37 | } else if (code == clear) { // Clear 38 | width = 1 + litWidth; 39 | hi = eof; 40 | overflow = 1 << width; 41 | last = DECODER_INVALID_CODE; 42 | continue; 43 | } else if (code == eof) { // End 44 | flush(); 45 | return true; 46 | } else if (code <= hi) { 47 | u16 c = code; 48 | uint i = output.size() - 1; 49 | if (code == hi && last != DECODER_INVALID_CODE) { 50 | // code == hi is a special case which expands to the last expansion 51 | // followed by the head of the last expansion. To find the head, we walk 52 | // the prefix chain until we find a literal code. 53 | c = last; 54 | while (c >= clear) 55 | c = prefix[c]; 56 | output[i] = c; 57 | i--; 58 | c = last; 59 | } 60 | // Copy the suffix chain into output and then write that to w. 61 | while (c >= clear) { 62 | output[i] = suffix[c]; 63 | i--; 64 | c = prefix[c]; 65 | } 66 | output[i] = c; 67 | std::copy(output.begin() + i, output.end(), output.begin() + o); 68 | o += std::distance(output.begin() + i, output.end()); 69 | if (last != DECODER_INVALID_CODE) { 70 | // Save what the hi code expands to 71 | suffix[hi] = c; 72 | prefix[hi] = last; 73 | } 74 | } else { // Error 75 | flush(); 76 | return false; 77 | } 78 | 79 | last = code; 80 | hi++; 81 | if (hi >= overflow) { 82 | if (hi > overflow) { 83 | flush(); 84 | return false; 85 | } 86 | 87 | if (width == MAX_WIDTH) { 88 | last = DECODER_INVALID_CODE; 89 | // Undo the d.hi++ a few lines above, so that (1) we maintain 90 | // the invariant that d.hi < d.overflow, and (2) d.hi does not 91 | // eventually overflow a uint16. 92 | hi--; 93 | } else { 94 | width++; 95 | overflow = 1 << width; 96 | } 97 | } 98 | if (o >= FLUSH_BUFFER) { 99 | flush(); 100 | } 101 | } 102 | 103 | flush(); 104 | return true; 105 | } 106 | 107 | LZWReader::LZWReader(int minCodeSize, std::function flushFunction) : litWidth(minCodeSize), flushFn(flushFunction) { 108 | width = 1 + litWidth; 109 | clear = 1 << litWidth; 110 | eof = clear + 1; 111 | hi = clear + 1; 112 | overflow = 1 << width; 113 | last = DECODER_INVALID_CODE; 114 | 115 | suffix = std::vector(1 << MAX_WIDTH); 116 | prefix = std::vector(1 << MAX_WIDTH); 117 | output = std::vector(2 * (1 << MAX_WIDTH)); 118 | } 119 | 120 | void LZWReader::flush(void) { 121 | if (flushFn && o > 0) { 122 | flushFn(output.begin(), output.begin() + o); 123 | } 124 | o = 0; 125 | } 126 | -------------------------------------------------------------------------------- /bootloader/source/arm9clear.arm.c: -------------------------------------------------------------------------------- 1 | #define ARM9 2 | #undef ARM7 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "boot.h" 15 | 16 | /*------------------------------------------------------------------------- 17 | resetMemory2_ARM9 18 | Clears the ARM9's DMA channels and resets video memory 19 | Written by Darkain. 20 | Modified by Chishm: 21 | * Changed MultiNDS specific stuff 22 | --------------------------------------------------------------------------*/ 23 | void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9 (void) 24 | { 25 | register int i; 26 | // int reg; 27 | 28 | //clear out ARM9 DMA channels 29 | for (i=0; i<4; i++) { 30 | DMA_CR(i) = 0; 31 | DMA_SRC(i) = 0; 32 | DMA_DEST(i) = 0; 33 | TIMER_CR(i) = 0; 34 | TIMER_DATA(i) = 0; 35 | // for(reg=0; reg<0x1c; reg+=4)*((u32*)(0x04004104 + ((i*0x1c)+reg))) = 0;//Reset NDMA. 36 | } 37 | 38 | VRAM_CR = (VRAM_CR & 0xffff0000) | 0x00008080 ; 39 | 40 | vu16 *mainregs = (vu16*)0x04000000; 41 | vu16 *subregs = (vu16*)0x04001000; 42 | 43 | for (i=0; i<43; i++) { 44 | mainregs[i] = 0; 45 | subregs[i] = 0; 46 | } 47 | 48 | REG_DISPSTAT = 0; 49 | 50 | VRAM_A_CR = 0; 51 | VRAM_B_CR = 0; 52 | VRAM_D_CR = 0; 53 | VRAM_E_CR = 0; 54 | VRAM_F_CR = 0; 55 | VRAM_G_CR = 0; 56 | VRAM_H_CR = 0; 57 | VRAM_I_CR = 0; 58 | REG_POWERCNT = 0x820F; 59 | //set shared ram to ARM7 60 | WRAM_CR = 0x03; 61 | // REG_EXMEMCNT = 0xE880; 62 | 63 | // Return to passme loop 64 | *((vu32*)0x02FFFE04) = (u32)0xE59FF018; // ldr pc, 0x02FFFE24 65 | *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; // Set ARM9 Loop address 66 | 67 | asm volatile( 68 | "\tbx %0\n" 69 | : : "r" (0x02FFFE04) 70 | ); 71 | while(1); 72 | } 73 | 74 | /* 75 | void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) initMBK_ARM9 (void) 76 | { 77 | 78 | *((vu32*)REG_MBK1)=0x8C888480; 79 | *((vu32*)REG_MBK2)=0x8D898581; 80 | *((vu32*)REG_MBK3)=0x9C999591; 81 | *((vu32*)REG_MBK4)=0x8D898581; 82 | *((vu32*)REG_MBK5)=0x9D999591; 83 | 84 | REG_MBK6=0x080037C0; 85 | REG_MBK7=0x07C03000; 86 | REG_MBK8=0x00003000; 87 | REG_MBK9=0xFF000000; 88 | 89 | // Return to passme loop 90 | *((vu32*)0x02FFFE04) = (u32)0xE59FF018; // ldr pc, 0x02FFFE24 91 | *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; // Set ARM9 Loop address 92 | 93 | asm volatile( 94 | "\tbx %0\n" 95 | : : "r" (0x02FFFE04) 96 | ); 97 | while(1); 98 | } 99 | */ 100 | 101 | /*------------------------------------------------------------------------- 102 | startBinary_ARM9 103 | Jumps to the ARM9 NDS binary in sync with the display and ARM7 104 | Written by Darkain. 105 | Modified by Chishm: 106 | * Removed MultiNDS specific stuff 107 | --------------------------------------------------------------------------*/ 108 | void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) startBinary_ARM9 (void) 109 | { 110 | // REG_SCFG_CLK = 0x87; 111 | // REG_SCFG_RST = 0x0001; 112 | // REG_SCFG_MC = 0x0018; 113 | 114 | REG_IME=0; 115 | REG_EXMEMCNT = 0xE880; 116 | // set ARM9 load address to 0 and wait for it to change again 117 | ARM9_START_FLAG = 0; 118 | while(REG_VCOUNT!=191); 119 | while(REG_VCOUNT==191); 120 | while ( ARM9_START_FLAG != 1 ); 121 | VoidFn arm9code = *(VoidFn*)(0x2FFFE24); 122 | arm9code(); 123 | while(1); 124 | } 125 | 126 | -------------------------------------------------------------------------------- /arm9/source/tonccpy.c: -------------------------------------------------------------------------------- 1 | #include "tonccpy.h" 2 | //# tonccpy.c 3 | 4 | //! VRAM-safe cpy. 5 | /*! This version mimics memcpy in functionality, with 6 | the benefit of working for VRAM as well. It is also 7 | slightly faster than the original memcpy, but faster 8 | implementations can be made. 9 | \param dst Destination pointer. 10 | \param src Source pointer. 11 | \param size Fill-length in bytes. 12 | \note The pointers and size need not be word-aligned. 13 | */ 14 | void tonccpy(void *dst, const void *src, uint size) 15 | { 16 | if(size==0 || dst==NULL || src==NULL) 17 | return; 18 | 19 | uint count; 20 | u16 *dst16; // hword destination 21 | u8 *src8; // byte source 22 | 23 | // Ideal case: copy by 4x words. Leaves tail for later. 24 | if( ((u32)src|(u32)dst)%4==0 && size>=4) 25 | { 26 | u32 *src32= (u32*)src, *dst32= (u32*)dst; 27 | 28 | count= size/4; 29 | uint tmp= count&3; 30 | count /= 4; 31 | 32 | // Duff's Device, good friend! 33 | switch(tmp) { 34 | do { *dst32++ = *src32++; 35 | case 3: *dst32++ = *src32++; 36 | case 2: *dst32++ = *src32++; 37 | case 1: *dst32++ = *src32++; 38 | case 0: ; } while(count--); 39 | } 40 | 41 | // Check for tail 42 | size &= 3; 43 | if(size == 0) 44 | return; 45 | 46 | src8= (u8*)src32; 47 | dst16= (u16*)dst32; 48 | } 49 | else // Unaligned. 50 | { 51 | uint dstOfs= (u32)dst&1; 52 | src8= (u8*)src; 53 | dst16= (u16*)(dst-dstOfs); 54 | 55 | // Head: 1 byte. 56 | if(dstOfs != 0) 57 | { 58 | *dst16= (*dst16 & 0xFF) | *src8++<<8; 59 | dst16++; 60 | if(--size==0) 61 | return; 62 | } 63 | } 64 | 65 | // Unaligned main: copy by 2x byte. 66 | count= size/2; 67 | while(count--) 68 | { 69 | *dst16++ = src8[0] | src8[1]<<8; 70 | src8 += 2; 71 | } 72 | 73 | // Tail: 1 byte. 74 | if(size&1) 75 | *dst16= (*dst16 &~ 0xFF) | *src8; 76 | } 77 | //# toncset.c 78 | 79 | //! VRAM-safe memset, internal routine. 80 | /*! This version mimics memset in functionality, with 81 | the benefit of working for VRAM as well. It is also 82 | slightly faster than the original memset. 83 | \param dst Destination pointer. 84 | \param fill Word to fill with. 85 | \param size Fill-length in bytes. 86 | \note The \a dst pointer and \a size need not be 87 | word-aligned. In the case of unaligned fills, \a fill 88 | will be masked off to match the situation. 89 | */ 90 | void __toncset(void *dst, u32 fill, uint size) 91 | { 92 | if(size==0 || dst==NULL) 93 | return; 94 | 95 | uint left= (u32)dst&3; 96 | u32 *dst32= (u32*)(dst-left); 97 | u32 count, mask; 98 | 99 | // Unaligned head. 100 | if(left != 0) 101 | { 102 | // Adjust for very small stint. 103 | if(left+size<4) 104 | { 105 | mask= BIT_MASK(size*8)<<(left*8); 106 | *dst32= (*dst32 &~ mask) | (fill & mask); 107 | return; 108 | } 109 | 110 | mask= BIT_MASK(left*8); 111 | *dst32= (*dst32 & mask) | (fill&~mask); 112 | dst32++; 113 | size -= 4-left; 114 | } 115 | 116 | // Main stint. 117 | count= size/4; 118 | uint tmp= count&3; 119 | count /= 4; 120 | 121 | switch(tmp) { 122 | do { *dst32++ = fill; 123 | case 3: *dst32++ = fill; 124 | case 2: *dst32++ = fill; 125 | case 1: *dst32++ = fill; 126 | case 0: ; } while(count--); 127 | } 128 | 129 | // Tail 130 | size &= 3; 131 | if(size) 132 | { 133 | mask= BIT_MASK(size*8); 134 | *dst32= (*dst32 &~ mask) | (fill & mask); 135 | } 136 | } -------------------------------------------------------------------------------- /bootloader/arm9code/mpu_reset.s: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2006 - 2015 Dave Murphy (WinterMute) 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 | */ 18 | 19 | #include 20 | 21 | .text 22 | .align 4 23 | 24 | .arm 25 | 26 | .arch armv5te 27 | .cpu arm946e-s 28 | 29 | @--------------------------------------------------------------------------------- 30 | .global _start 31 | .type _start STT_FUNC 32 | @--------------------------------------------------------------------------------- 33 | _start: 34 | @--------------------------------------------------------------------------------- 35 | @ Switch off MPU 36 | mrc p15, 0, r0, c1, c0, 0 37 | bic r0, r0, #PROTECT_ENABLE 38 | mcr p15, 0, r0, c1, c0, 0 39 | 40 | 41 | adr r12, mpu_initial_data 42 | ldmia r12, {r0-r10} 43 | 44 | mcr p15, 0, r0, c2, c0, 0 45 | mcr p15, 0, r0, c2, c0, 1 46 | mcr p15, 0, r1, c3, c0, 0 47 | mcr p15, 0, r2, c5, c0, 2 48 | mcr p15, 0, r3, c5, c0, 3 49 | mcr p15, 0, r4, c6, c0, 0 50 | mcr p15, 0, r5, c6, c1, 0 51 | mcr p15, 0, r6, c6, c3, 0 52 | mcr p15, 0, r7, c6, c4, 0 53 | mcr p15, 0, r8, c6, c6, 0 54 | mcr p15, 0, r9, c6, c7, 0 55 | mcr p15, 0, r10, c9, c1, 0 56 | 57 | mov r0, #0 58 | mcr p15, 0, r0, c6, c2, 0 @ PU Protection Unit Data/Unified Region 2 59 | mcr p15, 0, r0, c6, c5, 0 @ PU Protection Unit Data/Unified Region 5 60 | 61 | mrc p15, 0, r0, c9, c1, 0 @ DTCM 62 | mov r0, r0, lsr #12 @ base 63 | mov r0, r0, lsl #12 @ size 64 | add r0, r0, #0x4000 @ dtcm top 65 | 66 | sub r0, r0, #4 @ irq vector 67 | mov r1, #0 68 | str r1, [r0] 69 | sub r0, r0, #4 @ IRQ1 Check Bits 70 | str r1, [r0] 71 | 72 | sub r0, r0, #128 73 | bic r0, r0, #7 74 | 75 | msr cpsr_c, #0xd3 @ svc mode 76 | mov sp, r0 77 | sub r0, r0, #128 78 | msr cpsr_c, #0xd2 @ irq mode 79 | mov sp, r0 80 | sub r0, r0, #128 81 | msr cpsr_c, #0xdf @ system mode 82 | mov sp, r0 83 | 84 | @ enable cache & tcm 85 | mrc p15, 0, r0, c1, c0, 0 86 | ldr r1,= ITCM_ENABLE | DTCM_ENABLE | ICACHE_ENABLE | DCACHE_ENABLE 87 | orr r0,r0,r1 88 | mcr p15, 0, r0, c1, c0, 0 89 | 90 | ldr r10, =0x2FFFE04 91 | ldr r0, =0xE59FF018 92 | str r0, [r10] 93 | add r1, r10, #0x20 94 | str r10, [r1] 95 | bx r10 96 | 97 | .pool 98 | 99 | mpu_initial_data: 100 | .word 0x00000042 @ p15,0,c2,c0,0..1,r0 ;PU Cachability Bits for Data/Unified+Instruction Protection Region 101 | .word 0x00000002 @ p15,0,c3,c0,0,r1 ;PU Write-Bufferability Bits for Data Protection Regions 102 | .word 0x15111011 @ p15,0,c5,c0,2,r2 ;PU Extended Access Permission Data/Unified Protection Region 103 | .word 0x05100011 @ p15,0,c5,c0,3,r3 ;PU Extended Access Permission Instruction Protection Region 104 | .word 0x04000033 @ p15,0,c6,c0,0,r4 ;PU Protection Unit Data/Unified Region 0 105 | .word 0x0200002b @ p15,0,c6,c1,0,r5 ;PU Protection Unit Data/Unified Region 1 4MB 106 | .word 0x08000035 @ p15,0,c6,c3,0,r6 ;PU Protection Unit Data/Unified Region 3 107 | .word 0x0300001b @ p15,0,c6,c4,0,r7 ;PU Protection Unit Data/Unified Region 4 108 | .word 0xffff001d @ p15,0,c6,c6,0,r8 ;PU Protection Unit Data/Unified Region 6 109 | .word 0x02fff017 @ p15,0,c6,c7,0,r9 ;PU Protection Unit Data/Unified Region 7 4KB 110 | .word 0x0300000a @ p15,0,c9,c1,0,r10 ;TCM Data TCM Base and Virtual Size 111 | -------------------------------------------------------------------------------- /bootloader/source/io_dldi.s: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | 3 | Copyright (C) 2005 Michael "Chishm" Chisholm 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | If you use this code, please give due credit and email me about your 20 | project at chishm@hotmail.com 21 | ------------------------------------------------------------------*/ 22 | @--------------------------------------------------------------------------------- 23 | .align 4 24 | .arm 25 | .global _dldi_start 26 | .global _io_dldi 27 | @--------------------------------------------------------------------------------- 28 | .equ FEATURE_MEDIUM_CANREAD, 0x00000001 29 | .equ FEATURE_MEDIUM_CANWRITE, 0x00000002 30 | .equ FEATURE_SLOT_GBA, 0x00000010 31 | .equ FEATURE_SLOT_NDS, 0x00000020 32 | 33 | 34 | _dldi_start: 35 | #ifndef NO_DLDI 36 | 37 | @--------------------------------------------------------------------------------- 38 | @ Driver patch file standard header -- 16 bytes 39 | #ifdef STANDARD_DLDI 40 | .word 0xBF8DA5ED @ Magic number to identify this region 41 | #else 42 | .word 0xBF8DA5EE @ Magic number to identify this region 43 | #endif 44 | .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) 45 | .byte 0x01 @ Version number 46 | .byte 0x0e @ 16KiB @ Log [base-2] of the size of this driver in bytes. 47 | .byte 0x00 @ Sections to fix 48 | .byte 0x0e @ 16KiB @ Log [base-2] of the allocated space in bytes. 49 | 50 | @--------------------------------------------------------------------------------- 51 | @ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes 52 | .align 4 53 | .asciz "Loader (No interface)" 54 | 55 | @--------------------------------------------------------------------------------- 56 | @ Offsets to important sections within the data -- 32 bytes 57 | .align 6 58 | .word _dldi_start @ data start 59 | .word _dldi_end @ data end 60 | .word 0x00000000 @ Interworking glue start -- Needs address fixing 61 | .word 0x00000000 @ Interworking glue end 62 | .word 0x00000000 @ GOT start -- Needs address fixing 63 | .word 0x00000000 @ GOT end 64 | .word 0x00000000 @ bss start -- Needs setting to zero 65 | .word 0x00000000 @ bss end 66 | @--------------------------------------------------------------------------------- 67 | @ IO_INTERFACE data -- 32 bytes 68 | _io_dldi: 69 | .ascii "DLDI" @ ioType 70 | .word 0x00000000 @ Features 71 | .word _DLDI_startup @ 72 | .word _DLDI_isInserted @ 73 | .word _DLDI_readSectors @ Function pointers to standard device driver functions 74 | .word _DLDI_writeSectors @ 75 | .word _DLDI_clearStatus @ 76 | .word _DLDI_shutdown @ 77 | 78 | 79 | @--------------------------------------------------------------------------------- 80 | 81 | _DLDI_startup: 82 | _DLDI_isInserted: 83 | _DLDI_readSectors: 84 | _DLDI_writeSectors: 85 | _DLDI_clearStatus: 86 | _DLDI_shutdown: 87 | mov r0, #0x00 @ Return false for every function 88 | bx lr 89 | 90 | 91 | 92 | @--------------------------------------------------------------------------------- 93 | .align 94 | .pool 95 | 96 | .space (_dldi_start + 16384) - . @ Fill to 16KiB 97 | 98 | _dldi_end: 99 | .end 100 | @--------------------------------------------------------------------------------- 101 | #else 102 | @--------------------------------------------------------------------------------- 103 | @ IO_INTERFACE data -- 32 bytes 104 | _io_dldi: 105 | .ascii "DLDI" @ ioType 106 | .word 0x00000000 @ Features 107 | .word _DLDI_startup @ 108 | .word _DLDI_isInserted @ 109 | .word _DLDI_readSectors @ Function pointers to standard device driver functions 110 | .word _DLDI_writeSectors @ 111 | .word _DLDI_clearStatus @ 112 | .word _DLDI_shutdown @ 113 | 114 | _DLDI_startup: 115 | _DLDI_isInserted: 116 | _DLDI_readSectors: 117 | _DLDI_writeSectors: 118 | _DLDI_clearStatus: 119 | _DLDI_shutdown: 120 | mov r0, #0x00 @ Return false for every function 121 | bx lr 122 | 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /bootloader/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM) 6 | endif 7 | 8 | -include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | #--------------------------------------------------------------------------------- 15 | TARGET := load 16 | BUILD := build 17 | SOURCES := source 18 | INCLUDES := build 19 | SPECS := specs 20 | 21 | #--------------------------------------------------------------------------------- 22 | # options for code generation 23 | #--------------------------------------------------------------------------------- 24 | ARCH := -mthumb -mthumb-interwork 25 | 26 | CFLAGS := -g -Wall -Os\ 27 | -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ 28 | -ffast-math \ 29 | $(ARCH) 30 | 31 | CFLAGS += $(INCLUDE) $(EXTRA_CFLAGS) -DARM7 32 | 33 | ASFLAGS := -g $(ARCH) $(EXTRA_CFLAGS) $(INCLUDE) 34 | LDFLAGS = -nostartfiles -T $(TOPDIR)/load.ld -g $(ARCH) -Wl,-Map,$(TARGET).map 35 | 36 | LIBS := 37 | 38 | #--------------------------------------------------------------------------------- 39 | # list of directories containing libraries, this must be the top level containing 40 | # include and lib 41 | #--------------------------------------------------------------------------------- 42 | LIBDIRS := $(LIBNDS) 43 | 44 | 45 | #--------------------------------------------------------------------------------- 46 | # no real need to edit anything past this point unless you need to add additional 47 | # rules for different file extensions 48 | #--------------------------------------------------------------------------------- 49 | ifneq ($(BUILD),$(notdir $(CURDIR))) 50 | #--------------------------------------------------------------------------------- 51 | 52 | export TOPDIR := $(CURDIR) 53 | export LOADBIN ?= $(CURDIR)/../data/$(TARGET).bin 54 | export LOADELF := $(CURDIR)/$(TARGET).elf 55 | export DEPSDIR := $(CURDIR)/$(BUILD) 56 | 57 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 58 | 59 | export CC := $(PREFIX)gcc 60 | export CXX := $(PREFIX)g++ 61 | export AR := $(PREFIX)ar 62 | export OBJCOPY := $(PREFIX)objcopy 63 | 64 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 65 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 66 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 67 | 68 | export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 69 | 70 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 71 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 72 | -I$(CURDIR)/$(BUILD) 73 | 74 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 75 | 76 | #--------------------------------------------------------------------------------- 77 | # use CC for linking standard C 78 | #--------------------------------------------------------------------------------- 79 | export LD := $(CC) 80 | #--------------------------------------------------------------------------------- 81 | 82 | .PHONY: $(BUILD) clean 83 | 84 | #--------------------------------------------------------------------------------- 85 | $(BUILD): 86 | @[ -d $@ ] || mkdir -p $@ 87 | @$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile 88 | 89 | #--------------------------------------------------------------------------------- 90 | clean: 91 | @echo clean ... 92 | @rm -fr $(BUILD) *.elf *.bin 93 | 94 | #--------------------------------------------------------------------------------- 95 | else 96 | 97 | DEPENDS := $(OFILES:.o=.d) 98 | 99 | #--------------------------------------------------------------------------------- 100 | # main targets 101 | #--------------------------------------------------------------------------------- 102 | $(LOADBIN) : $(LOADELF) 103 | @mkdir -p ../../data 104 | @$(OBJCOPY) -O binary $< $@ 105 | @echo built ... $(notdir $@) 106 | 107 | $(LOADELF) : $(OFILES) 108 | @echo linking $(notdir $@) 109 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 110 | 111 | arm9mpu_reset.o: mpu_reset.bin 112 | 113 | mpu_reset.bin: mpu_reset.elf 114 | $(OBJCOPY) -O binary $< $@ 115 | 116 | mpu_reset.elf: $(TOPDIR)/arm9code/mpu_reset.s 117 | $(CC) $(ASFLAGS) -Ttext=0 -x assembler-with-cpp -nostartfiles -nostdlib $< -o $@ 118 | 119 | -include $(DEPENDS) 120 | #--------------------------------------------------------------------------------------- 121 | endif 122 | #--------------------------------------------------------------------------------------- 123 | -------------------------------------------------------------------------------- /arm9/source/nds_loader_arm9.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | Copyright (C) 2005 - 2010 3 | Michael "Chishm" Chisholm 4 | Dave "WinterMute" Murphy 5 | 6 | This program is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU General Public License 8 | as published by the Free Software Foundation; either version 2 9 | of the License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | 20 | ------------------------------------------------------------------*/ 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include "load_bin.h" 30 | 31 | #include "nds_loader_arm9.h" 32 | #define LCDC_BANK_C (u16*)0x06840000 33 | #define STORED_FILE_CLUSTER (*(((u32*)LCDC_BANK_C) + 1)) 34 | #define INIT_DISC (*(((u32*)LCDC_BANK_C) + 2)) 35 | 36 | #define STORED_FILE_CLUSTER_OFFSET 4 37 | #define INIT_DISC_OFFSET 8 38 | #define ARG_START_OFFSET 16 39 | #define ARG_SIZE_OFFSET 20 40 | #define HAVE_DSISD_OFFSET 28 41 | #define DSIMODE_OFFSET 32 42 | 43 | typedef signed int addr_t; 44 | typedef unsigned char data_t; 45 | 46 | #define FIX_ALL 0x01 47 | #define FIX_GLUE 0x02 48 | #define FIX_GOT 0x04 49 | #define FIX_BSS 0x08 50 | 51 | static addr_t readAddr (data_t *mem, addr_t offset) { 52 | return ((addr_t*)mem)[offset/sizeof(addr_t)]; 53 | } 54 | 55 | static void writeAddr (data_t *mem, addr_t offset, addr_t value) { 56 | ((addr_t*)mem)[offset/sizeof(addr_t)] = value; 57 | } 58 | 59 | static void vramcpy (void* dst, const void* src, int len) 60 | { 61 | u16* dst16 = (u16*)dst; 62 | u16* src16 = (u16*)src; 63 | 64 | for ( ; len > 0; len -= 2) { 65 | *dst16++ = *src16++; 66 | } 67 | } 68 | 69 | int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, int argc, const char** argv) 70 | { 71 | char* argStart; 72 | u16* argData; 73 | u16 argTempVal = 0; 74 | int argSize; 75 | const char* argChar; 76 | 77 | irqDisable(IRQ_ALL); 78 | 79 | // Direct CPU access to VRAM bank C 80 | VRAM_C_CR = VRAM_ENABLE | VRAM_C_LCD; 81 | // Load the loader/patcher into the correct address 82 | vramcpy (LCDC_BANK_C, loader, loaderSize); 83 | 84 | // Set the parameters for the loader 85 | // STORED_FILE_CLUSTER = cluster; 86 | writeAddr ((data_t*) LCDC_BANK_C, STORED_FILE_CLUSTER_OFFSET, cluster); 87 | // INIT_DISC = initDisc; 88 | writeAddr ((data_t*) LCDC_BANK_C, INIT_DISC_OFFSET, initDisc); 89 | 90 | writeAddr ((data_t*) LCDC_BANK_C, DSIMODE_OFFSET, isDSiMode()); 91 | if(argv[0][0]=='s' && argv[0][1]=='d') { 92 | writeAddr ((data_t*) LCDC_BANK_C, HAVE_DSISD_OFFSET, 1); 93 | } 94 | 95 | // Give arguments to loader 96 | argStart = (char*)LCDC_BANK_C + readAddr((data_t*)LCDC_BANK_C, ARG_START_OFFSET); 97 | argStart = (char*)(((int)argStart + 3) & ~3); // Align to word 98 | argData = (u16*)argStart; 99 | argSize = 0; 100 | 101 | for (; argc > 0 && *argv; ++argv, --argc) 102 | { 103 | for (argChar = *argv; *argChar != 0; ++argChar, ++argSize) 104 | { 105 | if (argSize & 1) 106 | { 107 | argTempVal |= (*argChar) << 8; 108 | *argData = argTempVal; 109 | ++argData; 110 | } 111 | else 112 | { 113 | argTempVal = *argChar; 114 | } 115 | } 116 | if (argSize & 1) 117 | { 118 | *argData = argTempVal; 119 | ++argData; 120 | } 121 | argTempVal = 0; 122 | ++argSize; 123 | } 124 | *argData = argTempVal; 125 | 126 | writeAddr ((data_t*) LCDC_BANK_C, ARG_START_OFFSET, (addr_t)argStart - (addr_t)LCDC_BANK_C); 127 | writeAddr ((data_t*) LCDC_BANK_C, ARG_SIZE_OFFSET, argSize); 128 | 129 | irqDisable(IRQ_ALL); 130 | 131 | // Give the VRAM to the ARM7 132 | VRAM_C_CR = VRAM_ENABLE | VRAM_C_ARM7_0x06000000; 133 | // Reset into a passme loop 134 | REG_EXMEMCNT |= ARM7_OWNS_ROM | ARM7_OWNS_CARD; 135 | 136 | *((vu32*)0x02FFFFFC) = 0; 137 | *((vu32*)0x02FFFE04) = (u32)0xE59FF018; 138 | *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; 139 | 140 | resetARM7(0x06000000); 141 | 142 | swiSoftReset(); 143 | return true; 144 | } 145 | 146 | int runNdsFile (const char* filename, int argc, const char** argv) { 147 | 148 | struct stat st; 149 | char filePath[PATH_MAX]; 150 | int pathLen; 151 | const char* args[1]; 152 | 153 | if (stat (filename, &st) < 0) { 154 | return 1; 155 | } 156 | 157 | if (argc <= 0 || !argv) { 158 | // Construct a command line if we weren't supplied with one 159 | if (!getcwd (filePath, PATH_MAX)) { 160 | return 2; 161 | } 162 | pathLen = strlen (filePath); 163 | strcpy (filePath + pathLen, filename); 164 | args[0] = filePath; 165 | argv = args; 166 | } 167 | 168 | return runNds (load_bin, load_bin_size, st.st_ino, true, argc, argv); 169 | } 170 | 171 | -------------------------------------------------------------------------------- /bootloader/source/load_crt0.s: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | 3 | Copyright (C) 2005 Michael "Chishm" Chisholm 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | If you use this code, please give due credit and email me about your 20 | project at chishm@hotmail.com 21 | ------------------------------------------------------------------*/ 22 | 23 | @--------------------------------------------------------------------------------- 24 | .section ".init" 25 | .global _start 26 | .global storedFileCluster 27 | .global initDisc 28 | .global wantToPatchDLDI 29 | .global argStart 30 | .global argSize 31 | .global dsiSD 32 | .global dsiMode 33 | @--------------------------------------------------------------------------------- 34 | .align 4 35 | .arm 36 | @--------------------------------------------------------------------------------- 37 | _start: 38 | @--------------------------------------------------------------------------------- 39 | b startUp 40 | 41 | storedFileCluster: 42 | .word 0x0FFFFFFF @ default BOOT.NDS 43 | initDisc: 44 | .word 0x00000001 @ init the disc by default 45 | wantToPatchDLDI: 46 | .word 0x00000001 @ by default patch the DLDI section of the loaded NDS 47 | @ Used for passing arguments to the loaded app 48 | argStart: 49 | .word _end - _start 50 | argSize: 51 | .word 0x00000000 52 | dldiOffset: 53 | .word _dldi_start - _start 54 | dsiSD: 55 | .word 0 56 | dsiMode: 57 | .word 0 58 | 59 | startUp: 60 | mov r0, #0x04000000 61 | mov r1, #0 62 | str r1, [r0,#0x208] @ REG_IME 63 | str r1, [r0,#0x210] @ REG_IE 64 | str r1, [r0,#0x218] @ REG_AUXIE 65 | 66 | mov r0, #0x12 @ Switch to IRQ Mode 67 | msr cpsr, r0 68 | ldr sp, =__sp_irq @ Set IRQ stack 69 | 70 | mov r0, #0x13 @ Switch to SVC Mode 71 | msr cpsr, r0 72 | ldr sp, =__sp_svc @ Set SVC stack 73 | 74 | mov r0, #0x1F @ Switch to System Mode 75 | msr cpsr, r0 76 | ldr sp, =__sp_usr @ Set user stack 77 | 78 | ldr r0, =__bss_start @ Clear BSS section to 0x00 79 | ldr r1, =__bss_end 80 | sub r1, r1, r0 81 | bl ClearMem 82 | 83 | mov r0, #0 @ int argc 84 | mov r1, #0 @ char *argv[] 85 | ldr r3, =main 86 | bl _blx_r3_stub @ jump to user code 87 | 88 | @ If the user ever returns, restart 89 | b _start 90 | 91 | @--------------------------------------------------------------------------------- 92 | _blx_r3_stub: 93 | @--------------------------------------------------------------------------------- 94 | bx r3 95 | 96 | @--------------------------------------------------------------------------------- 97 | @ Clear memory to 0x00 if length != 0 98 | @ r0 = Start Address 99 | @ r1 = Length 100 | @--------------------------------------------------------------------------------- 101 | ClearMem: 102 | @--------------------------------------------------------------------------------- 103 | mov r2, #3 @ Round down to nearest word boundary 104 | add r1, r1, r2 @ Shouldn't be needed 105 | bics r1, r1, r2 @ Clear 2 LSB (and set Z) 106 | bxeq lr @ Quit if copy size is 0 107 | 108 | mov r2, #0 109 | ClrLoop: 110 | stmia r0!, {r2} 111 | subs r1, r1, #4 112 | bne ClrLoop 113 | bx lr 114 | 115 | @--------------------------------------------------------------------------------- 116 | @ Copy memory if length != 0 117 | @ r1 = Source Address 118 | @ r2 = Dest Address 119 | @ r4 = Dest Address + Length 120 | @--------------------------------------------------------------------------------- 121 | CopyMemCheck: 122 | @--------------------------------------------------------------------------------- 123 | sub r3, r4, r2 @ Is there any data to copy? 124 | @--------------------------------------------------------------------------------- 125 | @ Copy memory 126 | @ r1 = Source Address 127 | @ r2 = Dest Address 128 | @ r3 = Length 129 | @--------------------------------------------------------------------------------- 130 | CopyMem: 131 | @--------------------------------------------------------------------------------- 132 | mov r0, #3 @ These commands are used in cases where 133 | add r3, r3, r0 @ the length is not a multiple of 4, 134 | bics r3, r3, r0 @ even though it should be. 135 | bxeq lr @ Length is zero, so exit 136 | CIDLoop: 137 | ldmia r1!, {r0} 138 | stmia r2!, {r0} 139 | subs r3, r3, #4 140 | bne CIDLoop 141 | bx lr 142 | 143 | @--------------------------------------------------------------------------------- 144 | .align 145 | .pool 146 | .end 147 | @--------------------------------------------------------------------------------- 148 | -------------------------------------------------------------------------------- /arm7/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include build 20 | DATA := 21 | 22 | #--------------------------------------------------------------------------------- 23 | # options for code generation 24 | #--------------------------------------------------------------------------------- 25 | ARCH := -march=armv4t -mthumb -mthumb-interwork 26 | 27 | CFLAGS := -g -Wall -O2\ 28 | -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ 29 | -ffast-math \ 30 | $(ARCH) 31 | 32 | CFLAGS += $(INCLUDE) -DARM7 33 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti 34 | 35 | 36 | ASFLAGS := -g $(ARCH) 37 | LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map 38 | 39 | LIBS := -lnds7 40 | 41 | #--------------------------------------------------------------------------------- 42 | # list of directories containing libraries, this must be the top level containing 43 | # include and lib 44 | #--------------------------------------------------------------------------------- 45 | LIBDIRS := $(LIBNDS) 46 | 47 | 48 | #--------------------------------------------------------------------------------- 49 | # no real need to edit anything past this point unless you need to add additional 50 | # rules for different file extensions 51 | #--------------------------------------------------------------------------------- 52 | ifneq ($(BUILD),$(notdir $(CURDIR))) 53 | #--------------------------------------------------------------------------------- 54 | 55 | export ARM7ELF := $(CURDIR)/$(TARGET).elf 56 | export DEPSDIR := $(CURDIR)/$(BUILD) 57 | 58 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 59 | 60 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 61 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 62 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 63 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 64 | 65 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 66 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 67 | 68 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 69 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 70 | -I$(CURDIR)/$(BUILD) 71 | 72 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 73 | 74 | #--------------------------------------------------------------------------------- 75 | # use CXX for linking C++ projects, CC for standard C 76 | #--------------------------------------------------------------------------------- 77 | ifeq ($(strip $(CPPFILES)),) 78 | #--------------------------------------------------------------------------------- 79 | export LD := $(CC) 80 | #--------------------------------------------------------------------------------- 81 | else 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CXX) 84 | #--------------------------------------------------------------------------------- 85 | endif 86 | #--------------------------------------------------------------------------------- 87 | 88 | .PHONY: $(BUILD) clean 89 | 90 | #--------------------------------------------------------------------------------- 91 | $(BUILD): 92 | @[ -d $@ ] || mkdir -p $@ 93 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 94 | 95 | #--------------------------------------------------------------------------------- 96 | clean: 97 | @echo clean ... 98 | @rm -fr $(BUILD) *.elf 99 | 100 | #--------------------------------------------------------------------------------- 101 | else 102 | 103 | DEPENDS := $(OFILES:.o=.d) 104 | 105 | #--------------------------------------------------------------------------------- 106 | # main targets 107 | #--------------------------------------------------------------------------------- 108 | $(ARM7ELF) : $(OFILES) 109 | @echo linking $(notdir $@) 110 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 111 | 112 | #--------------------------------------------------------------------------------- 113 | # you need a rule like this for each extension you use as binary data 114 | #--------------------------------------------------------------------------------- 115 | %.bin.o : %.bin 116 | #--------------------------------------------------------------------------------- 117 | @echo $(notdir $<) 118 | @$(bin2o) 119 | 120 | -include $(DEPENDS) 121 | 122 | #--------------------------------------------------------------------------------------- 123 | endif 124 | #--------------------------------------------------------------------------------------- 125 | -------------------------------------------------------------------------------- /bootloader/load.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | MEMORY { 6 | 7 | vram : ORIGIN = 0x06000000, LENGTH = 128K 8 | } 9 | 10 | __vram_start = ORIGIN(vram); 11 | __vram_top = ORIGIN(vram)+ LENGTH(vram); 12 | __sp_irq = __vram_top - 0x60; 13 | __sp_svc = __sp_irq - 0x100; 14 | __sp_usr = __sp_svc - 0x100; 15 | 16 | __irq_flags = __vram_top - 8; 17 | __irq_vector = __vram_top - 4; 18 | 19 | SECTIONS 20 | { 21 | .init : 22 | { 23 | __text_start = . ; 24 | KEEP (*(.init)) 25 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 26 | } >vram = 0xff 27 | 28 | .plt : 29 | { 30 | *(.plt) 31 | } >vram = 0xff 32 | 33 | .text : /* ALIGN (4): */ 34 | { 35 | 36 | *(.text*) 37 | *(.stub) 38 | /* .gnu.warning sections are handled specially by elf32.em. */ 39 | *(.gnu.warning) 40 | *(.gnu.linkonce.t*) 41 | *(.glue_7) 42 | *(.glue_7t) 43 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 44 | } >vram = 0xff 45 | 46 | .fini : 47 | { 48 | KEEP (*(.fini)) 49 | } >vram =0xff 50 | 51 | __text_end = . ; 52 | 53 | .rodata : 54 | { 55 | *(.rodata) 56 | *all.rodata*(*) 57 | *(.roda) 58 | *(.rodata.*) 59 | *(.gnu.linkonce.r*) 60 | SORT(CONSTRUCTORS) 61 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 62 | } >vram = 0xff 63 | 64 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >vram 65 | __exidx_start = .; 66 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >vram 67 | __exidx_end = .; 68 | 69 | /* Ensure the __preinit_array_start label is properly aligned. We 70 | could instead move the label definition inside the section, but 71 | the linker would then create the section even if it turns out to 72 | be empty, which isn't pretty. */ 73 | . = ALIGN(32 / 8); 74 | PROVIDE (__preinit_array_start = .); 75 | .preinit_array : { KEEP (*(.preinit_array)) } >vram = 0xff 76 | PROVIDE (__preinit_array_end = .); 77 | PROVIDE (__init_array_start = .); 78 | .init_array : { KEEP (*(.init_array)) } >vram = 0xff 79 | PROVIDE (__init_array_end = .); 80 | PROVIDE (__fini_array_start = .); 81 | .fini_array : { KEEP (*(.fini_array)) } >vram = 0xff 82 | PROVIDE (__fini_array_end = .); 83 | 84 | .ctors : 85 | { 86 | /* gcc uses crtbegin.o to find the start of the constructors, so 87 | we make sure it is first. Because this is a wildcard, it 88 | doesn't matter if the user does not actually link against 89 | crtbegin.o; the linker won't look for a file to match a 90 | wildcard. The wildcard also means that it doesn't matter which 91 | directory crtbegin.o is in. */ 92 | KEEP (*crtbegin.o(.ctors)) 93 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 94 | KEEP (*(SORT(.ctors.*))) 95 | KEEP (*(.ctors)) 96 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 97 | } >vram = 0xff 98 | 99 | .dtors : 100 | { 101 | KEEP (*crtbegin.o(.dtors)) 102 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 103 | KEEP (*(SORT(.dtors.*))) 104 | KEEP (*(.dtors)) 105 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 106 | } >vram = 0xff 107 | 108 | .eh_frame : 109 | { 110 | KEEP (*(.eh_frame)) 111 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 112 | } >vram = 0xff 113 | 114 | .gcc_except_table : 115 | { 116 | *(.gcc_except_table) 117 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 118 | } >vram = 0xff 119 | .jcr : { KEEP (*(.jcr)) } >vram = 0 120 | .got : { *(.got.plt) *(.got) } >vram = 0 121 | 122 | 123 | .vram ALIGN(4) : 124 | { 125 | __vram_start = ABSOLUTE(.) ; 126 | *(.vram) 127 | *vram.*(.text) 128 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 129 | __vram_end = ABSOLUTE(.) ; 130 | } >vram = 0xff 131 | 132 | 133 | .data ALIGN(4) : { 134 | __data_start = ABSOLUTE(.); 135 | *(.data) 136 | *(.data.*) 137 | *(.gnu.linkonce.d*) 138 | CONSTRUCTORS 139 | . = ALIGN(4); 140 | __data_end = ABSOLUTE(.) ; 141 | } >vram = 0xff 142 | 143 | 144 | 145 | .bss ALIGN(4) : 146 | { 147 | __bss_start = ABSOLUTE(.); 148 | __bss_start__ = ABSOLUTE(.); 149 | *(.dynbss) 150 | *(.gnu.linkonce.b*) 151 | *(.bss*) 152 | *(COMMON) 153 | . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ 154 | } >vram 155 | 156 | __bss_end = . ; 157 | __bss_end__ = . ; 158 | 159 | _end = . ; 160 | __end__ = . ; 161 | PROVIDE (end = _end); 162 | 163 | /* Stabs debugging sections. */ 164 | .stab 0 : { *(.stab) } 165 | .stabstr 0 : { *(.stabstr) } 166 | .stab.excl 0 : { *(.stab.excl) } 167 | .stab.exclstr 0 : { *(.stab.exclstr) } 168 | .stab.index 0 : { *(.stab.index) } 169 | .stab.indexstr 0 : { *(.stab.indexstr) } 170 | .comment 0 : { *(.comment) } 171 | /* DWARF debug sections. 172 | Symbols in the DWARF debugging sections are relative to the beginning 173 | of the section so we begin them at 0. */ 174 | /* DWARF 1 */ 175 | .debug 0 : { *(.debug) } 176 | .line 0 : { *(.line) } 177 | /* GNU DWARF 1 extensions */ 178 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 179 | .debug_sfnames 0 : { *(.debug_sfnames) } 180 | /* DWARF 1.1 and DWARF 2 */ 181 | .debug_aranges 0 : { *(.debug_aranges) } 182 | .debug_pubnames 0 : { *(.debug_pubnames) } 183 | /* DWARF 2 */ 184 | .debug_info 0 : { *(.debug_info) } 185 | .debug_abbrev 0 : { *(.debug_abbrev) } 186 | .debug_line 0 : { *(.debug_line) } 187 | .debug_frame 0 : { *(.debug_frame) } 188 | .debug_str 0 : { *(.debug_str) } 189 | .debug_loc 0 : { *(.debug_loc) } 190 | .debug_macinfo 0 : { *(.debug_macinfo) } 191 | /* SGI/MIPS DWARF 2 extensions */ 192 | .debug_weaknames 0 : { *(.debug_weaknames) } 193 | .debug_funcnames 0 : { *(.debug_funcnames) } 194 | .debug_typenames 0 : { *(.debug_typenames) } 195 | .debug_varnames 0 : { *(.debug_varnames) } 196 | .stack 0x80000 : { _stack = .; *(.stack) } 197 | /* These must appear regardless of . */ 198 | } 199 | -------------------------------------------------------------------------------- /hiyacfw_helper.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import os 3 | import sys 4 | import subprocess 5 | 6 | # use apply ips function for https://github.com/meunierd/python-ips 7 | 8 | import shutil 9 | import struct 10 | 11 | from os.path import getsize 12 | 13 | 14 | def unpack_int(string): 15 | """Read an n-byte big-endian integer from a byte string.""" 16 | (ret,) = struct.unpack_from('>I', b'\x00' * (4 - len(string)) + string) 17 | return ret 18 | 19 | def apply(patchpath, filepath): 20 | patch_size = getsize(patchpath) 21 | patchfile = open(patchpath, 'rb') 22 | target = open(filepath, 'r+b') 23 | 24 | if patchfile.read(5) != b'PATCH': 25 | raise Exception('Invalid patch header.') 26 | 27 | # Read First Record 28 | r = patchfile.read(3) 29 | while patchfile.tell() not in [patch_size, patch_size - 3]: 30 | # Unpack 3-byte pointers. 31 | offset = unpack_int(r) 32 | # Read size of data chunk 33 | r = patchfile.read(2) 34 | size = unpack_int(r) 35 | 36 | if size == 0: # RLE Record 37 | r = patchfile.read(2) 38 | rle_size = unpack_int(r) 39 | data = patchfile.read(1) * rle_size 40 | else: 41 | data = patchfile.read(size) 42 | 43 | # Write to file 44 | target.seek(offset) 45 | target.write(data) 46 | # Read Next Record 47 | r = patchfile.read(3) 48 | 49 | if patch_size - 3 == patchfile.tell(): 50 | trim_size = unpack_int(patchfile.read(3)) 51 | target.truncate(trim_size) 52 | 53 | # Cleanup 54 | target.close() 55 | patchfile.close() 56 | 57 | launcher_region = "" 58 | 59 | print('---HIYACFW HELPER---') 60 | print('This is an updated version for Au, USA, EUR, Jap DSI. Edited by LmN') 61 | print('Running self-check') 62 | dependencies = ['nand.bin', "00000002.app"] 63 | try: 64 | if os.name == 'nt': 65 | char = "\\" 66 | else: 67 | char = "/" 68 | 69 | if os.getcwd().split(char)[-1].replace("\\", "") != 'for PC': 70 | raise Exception('Script not placed in the HiyaCFW "for PC" directory. Please place the script in the correct location before proceeding.') 71 | for dependency in dependencies: 72 | if not os.path.isfile(dependency): 73 | raise Exception('File {} not found. Ensure you placed these in the directory.'.format(dependency)) 74 | with open('00000002.app', 'rb') as launcher: 75 | expected_sha1s = { 'usa': '1339bd7457484839f1d71f27de2f8da8098834b4', 'jap': '69c422a1ab1f26344a3d2b294ec714db362f57f0', 'eur': 'c5a3507181489f5190976a905b2953799e421363', 'aus': '8f79c6c1442d3e33d211454ec92bbe42c94a599d'} 76 | sha1 = hashlib.sha1() 77 | sha1.update(launcher.read()) 78 | for region, expected_sha1 in expected_sha1s.items(): 79 | if sha1.hexdigest() == expected_sha1: 80 | launcher_region = region 81 | if launcher_region == "": 82 | raise Exception('Launcher is not v512 of AUS, USA, EUR or JAP. Is your launcher the right version and decrypted?') 83 | except Exception as e: 84 | print('Self-check failed! {}'.format(e)) 85 | input('Press Enter to continue...') 86 | sys.exit() 87 | 88 | print('Decrypting NAND') 89 | try: 90 | if os.name == 'nt': 91 | subprocess.call(["twltool", "nandcrypt", "--in", "nand.bin"]) 92 | else: 93 | print("WARNING: Non-Windows operating system detected!") 94 | print("The script will continue, but please ensure that Wine is installed.") 95 | input("Press the Enter key to continue...") 96 | subprocess.call(["wine", "twltool", "nandcrypt", "--in", "nand.bin"]) 97 | 98 | except Exception as e: 99 | print('Error occured! Does this backup have the required NO$GBA footer? ({0})'.format(e)) 100 | input('Press Enter to continue...') 101 | sys.exit() 102 | 103 | print('\nExtracting ARM7/ARM9 BIOS from NAND') 104 | if os.name == 'nt': 105 | subprocess.call(["twltool", "boot2", "--in", "nand.bin"]) 106 | else: 107 | subprocess.call(["wine", "twltool", "boot2", "--in", "nand.bin"]) 108 | 109 | print('\nIPS patching ARM7/ARM9 BIOS') 110 | apply("bootloader files/bootloader arm7 patch.ips", "arm7.bin") 111 | apply("bootloader files/bootloader arm9 patch.ips", "arm9.bin") 112 | print('\nPrepending data to ARM9 BIOS') 113 | 114 | try: 115 | with open('bootloader files/bootloader arm9 append to start.bin', 'rb') as arm9_prepend, open('arm9.bin', 'rb') as arm9_bin, open('arm9_new.bin', 'ab') as arm9_new: 116 | arm9_new.write(arm9_prepend.read() + arm9_bin.read()) 117 | os.remove('arm9.bin') 118 | os.rename('arm9_new.bin', 'arm9.bin') 119 | except Exception as e: 120 | print('Error occured! Does the bootloader files folder exist?') 121 | input('Press Enter to continue...') 122 | sys.exit() 123 | 124 | print('\nGenerating new bootloader') 125 | if os.name == 'nt': 126 | subprocess.call(['bootloader files/ndstool', '-c', 'bootloader.nds', '-9', 'arm9.bin', '-7', 'arm7.bin', '-t', 'bootloader files/banner.bin', '-h', 'bootloader files/header.bin']) 127 | else: 128 | subprocess.call(['wine', 'bootloader files/ndstool', '-c', 'bootloader.nds', '-9', 'arm9.bin', '-7', 'arm7.bin', '-t', 'bootloader files/banner.bin', '-h', 'bootloader files/header.bin']) 129 | 130 | # wine twltool modcrypt --in "00000002.app" --out "00000002_dec.app" 131 | print('\nDecrypting launcher') 132 | if os.name == 'nt': 133 | subprocess.call(["twltool", "modcrypt", "--in", "00000002.app"]) 134 | else: 135 | subprocess.call(["wine", "twltool", "modcrypt", "--in", "00000002.app"]) 136 | 137 | print('\nIPS patching launcher') 138 | patch = "v1.4 Launcher (00000002.app) (JAP-KOR) patch.ips" if launcher_region == "jap" else "v1.4 Launcher (00000002.app) patch.ips" 139 | 140 | 141 | apply(patch, "00000002.app") 142 | 143 | print('\nMoving new files') 144 | if not os.path.isdir('Modified Files'): 145 | os.mkdir('Modified Files') 146 | os.rename('bootloader.nds', 'Modified Files/bootloader.nds') 147 | os.rename('00000002.app', 'Modified Files/00000002.app') 148 | 149 | print('Done!') 150 | print('Navigate to the Modified Files folder.') 151 | print('Copy bootloader.nds to the hiya folder on your <2GB SD card.') 152 | print('Copy 00000002.app to title/00030017/484e41XX/content folder on your <2GB SD card.') 153 | input('Press Enter to continue...') 154 | sys.exit() 155 | -------------------------------------------------------------------------------- /arm9/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | export LIBSLIM := $(CURDIR)/../libs/libslim/libslim 9 | 10 | include $(DEVKITARM)/ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | 14 | # If on a tagged commit, use the tag instead of the commit 15 | ifneq ($(shell echo $(shell git tag -l --points-at HEAD) | head -c 1),) 16 | GIT_VER := $(shell git tag -l --points-at HEAD) 17 | else 18 | GIT_VER := $(shell git describe --tags --match v[0-9]* --abbrev=7 | sed 's/-[0-9]*-g/-/') 19 | endif 20 | 21 | # Ensure version.h exists 22 | ifeq (,$(wildcard include/version.h)) 23 | $(shell mkdir -p include) 24 | $(shell touch include/version.h) 25 | endif 26 | 27 | # Print new version if changed 28 | ifeq (,$(findstring $(GIT_VER), $(shell cat include/version.h))) 29 | $(shell printf "#ifndef VERSION_HPP\n#define VERSION_HPP\n\n#define VER_NUMBER \"$(GIT_VER)\"\n\n#endif\n" > include/version.h) 30 | endif 31 | 32 | #--------------------------------------------------------------------------------- 33 | # BUILD is the directory where object files & intermediate files will be placed 34 | # SOURCES is a list of directories containing source code 35 | # INCLUDES is a list of directories containing extra header files 36 | # DATA is a list of directories containing binary files 37 | # GRAPHICS is a list of directories containing image files to be converted with grit 38 | # all directories are relative to this makefile 39 | #--------------------------------------------------------------------------------- 40 | BUILD := build 41 | SOURCES := source 42 | INCLUDES := include 43 | DATA := ../data 44 | GRAPHICS := graphics 45 | 46 | #--------------------------------------------------------------------------------- 47 | # options for code generation 48 | #--------------------------------------------------------------------------------- 49 | ARCH := -mthumb -mthumb-interwork 50 | 51 | CFLAGS := -g -Wall -O2\ 52 | -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ 53 | -ffast-math \ 54 | $(ARCH) 55 | 56 | CFLAGS += $(INCLUDE) -DARM9 57 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 58 | 59 | ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s 60 | 61 | LDFLAGS = -specs=../ds_arm9_hiya.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 62 | 63 | #--------------------------------------------------------------------------------- 64 | # any extra libraries we wish to link with the project 65 | #--------------------------------------------------------------------------------- 66 | LIBS := -lslim -lnds9 67 | 68 | #--------------------------------------------------------------------------------- 69 | # list of directories containing libraries, this must be the top level containing 70 | # include and lib 71 | #--------------------------------------------------------------------------------- 72 | LIBDIRS := $(LIBSLIM) $(LIBNDS) 73 | 74 | #--------------------------------------------------------------------------------- 75 | # no real need to edit anything past this point unless you need to add additional 76 | # rules for different file extensions 77 | #--------------------------------------------------------------------------------- 78 | ifneq ($(BUILD),$(notdir $(CURDIR))) 79 | #--------------------------------------------------------------------------------- 80 | 81 | export ARM9ELF := $(CURDIR)/$(TARGET).elf 82 | export DEPSDIR := $(CURDIR)/$(BUILD) 83 | 84 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 85 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ 86 | $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) 87 | 88 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 89 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 90 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 91 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 92 | BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp))) 93 | 94 | #--------------------------------------------------------------------------------- 95 | # use CXX for linking C++ projects, CC for standard C 96 | #--------------------------------------------------------------------------------- 97 | ifeq ($(strip $(CPPFILES)),) 98 | #--------------------------------------------------------------------------------- 99 | export LD := $(CC) 100 | #--------------------------------------------------------------------------------- 101 | else 102 | #--------------------------------------------------------------------------------- 103 | export LD := $(CXX) 104 | #--------------------------------------------------------------------------------- 105 | endif 106 | #--------------------------------------------------------------------------------- 107 | 108 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 109 | $(BMPFILES:.bmp=.o) \ 110 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 111 | 112 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 113 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 114 | -I$(CURDIR)/$(BUILD) 115 | 116 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 117 | 118 | .PHONY: $(BUILD) clean 119 | 120 | #--------------------------------------------------------------------------------- 121 | $(BUILD): 122 | @[ -d $@ ] || mkdir -p $@ 123 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 124 | 125 | #--------------------------------------------------------------------------------- 126 | clean: 127 | @echo clean ... 128 | @rm -fr $(BUILD) *.elf *.nds* *.bin 129 | 130 | #--------------------------------------------------------------------------------- 131 | else 132 | 133 | #--------------------------------------------------------------------------------- 134 | # main targets 135 | #--------------------------------------------------------------------------------- 136 | $(ARM9ELF) : $(OFILES) 137 | @echo linking $(notdir $@) 138 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 139 | 140 | #--------------------------------------------------------------------------------- 141 | # you need a rule like this for each extension you use as binary data 142 | #--------------------------------------------------------------------------------- 143 | %.bin.o : %.bin 144 | #--------------------------------------------------------------------------------- 145 | @echo $(notdir $<) 146 | @$(bin2o) 147 | 148 | #--------------------------------------------------------------------------------- 149 | %.s %.h : %.bmp 150 | #--------------------------------------------------------------------------------- 151 | grit $< -gb -gB8 -gzl -gT! -fts -o$* 152 | 153 | -include $(DEPSDIR)/*.d 154 | 155 | #--------------------------------------------------------------------------------------- 156 | endif 157 | #--------------------------------------------------------------------------------------- 158 | -------------------------------------------------------------------------------- /bootloader/source/sdmmc.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDMMC_H__ 2 | #define __SDMMC_H__ 3 | 4 | #include 5 | 6 | #define DATA32_SUPPORT 7 | 8 | #define SDMMC_BASE 0x04004800 9 | 10 | 11 | #define REG_SDCMD 0x00 12 | #define REG_SDPORTSEL 0x02 13 | #define REG_SDCMDARG 0x04 14 | #define REG_SDCMDARG0 0x04 15 | #define REG_SDCMDARG1 0x06 16 | #define REG_SDSTOP 0x08 17 | #define REG_SDRESP 0x0c 18 | #define REG_SDBLKCOUNT 0x0a 19 | 20 | #define REG_SDRESP0 0x0c 21 | #define REG_SDRESP1 0x0e 22 | #define REG_SDRESP2 0x10 23 | #define REG_SDRESP3 0x12 24 | #define REG_SDRESP4 0x14 25 | #define REG_SDRESP5 0x16 26 | #define REG_SDRESP6 0x18 27 | #define REG_SDRESP7 0x1a 28 | 29 | #define REG_SDSTATUS0 0x1c 30 | #define REG_SDSTATUS1 0x1e 31 | 32 | #define REG_SDIRMASK0 0x20 33 | #define REG_SDIRMASK1 0x22 34 | #define REG_SDCLKCTL 0x24 35 | 36 | #define REG_SDBLKLEN 0x26 37 | #define REG_SDOPT 0x28 38 | #define REG_SDFIFO 0x30 39 | 40 | #define REG_SDDATACTL 0xd8 41 | #define REG_SDRESET 0xe0 42 | #define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? 43 | 44 | #define REG_SDDATACTL32 0x100 45 | #define REG_SDBLKLEN32 0x104 46 | #define REG_SDBLKCOUNT32 0x108 47 | #define REG_SDFIFO32 0x10C 48 | 49 | #define REG_CLK_AND_WAIT_CTL 0x138 50 | #define REG_RESET_SDIO 0x1e0 51 | //The below defines are from linux kernel drivers/mmc tmio_mmc.h. 52 | /* Definitions for values the CTRL_STATUS register can take. */ 53 | #define TMIO_STAT0_CMDRESPEND 0x0001 54 | #define TMIO_STAT0_DATAEND 0x0004 55 | #define TMIO_STAT0_CARD_REMOVE 0x0008 56 | #define TMIO_STAT0_CARD_INSERT 0x0010 57 | #define TMIO_STAT0_SIGSTATE 0x0020 58 | #define TMIO_STAT0_WRPROTECT 0x0080 59 | #define TMIO_STAT0_CARD_REMOVE_A 0x0100 60 | #define TMIO_STAT0_CARD_INSERT_A 0x0200 61 | #define TMIO_STAT0_SIGSTATE_A 0x0400 62 | 63 | #define TMIO_STAT1_CMD_IDX_ERR 0x0001 64 | #define TMIO_STAT1_CRCFAIL 0x0002 65 | #define TMIO_STAT1_STOPBIT_ERR 0x0004 66 | #define TMIO_STAT1_DATATIMEOUT 0x0008 67 | #define TMIO_STAT1_RXOVERFLOW 0x0010 68 | #define TMIO_STAT1_TXUNDERRUN 0x0020 69 | #define TMIO_STAT1_CMDTIMEOUT 0x0040 70 | #define TMIO_STAT1_RXRDY 0x0100 71 | #define TMIO_STAT1_TXRQ 0x0200 72 | #define TMIO_STAT1_ILL_FUNC 0x2000 73 | #define TMIO_STAT1_CMD_BUSY 0x4000 74 | #define TMIO_STAT1_ILL_ACCESS 0x8000 75 | 76 | #define SDMC_NORMAL 0x00000000 77 | #define SDMC_ERR_COMMAND 0x00000001 78 | #define SDMC_ERR_CRC 0x00000002 79 | #define SDMC_ERR_END 0x00000004 80 | #define SDMC_ERR_TIMEOUT 0x00000008 81 | #define SDMC_ERR_FIFO_OVF 0x00000010 82 | #define SDMC_ERR_FIFO_UDF 0x00000020 83 | #define SDMC_ERR_WP 0x00000040 84 | #define SDMC_ERR_ABORT 0x00000080 85 | #define SDMC_ERR_FPGA_TIMEOUT 0x00000100 86 | #define SDMC_ERR_PARAM 0x00000200 87 | #define SDMC_ERR_R1_STATUS 0x00000800 88 | #define SDMC_ERR_NUM_WR_SECTORS 0x00001000 89 | #define SDMC_ERR_RESET 0x00002000 90 | #define SDMC_ERR_ILA 0x00004000 91 | #define SDMC_ERR_INFO_DETECT 0x00008000 92 | 93 | #define SDMC_STAT_ERR_UNKNOWN 0x00080000 94 | #define SDMC_STAT_ERR_CC 0x00100000 95 | #define SDMC_STAT_ERR_ECC_FAILED 0x00200000 96 | #define SDMC_STAT_ERR_CRC 0x00800000 97 | #define SDMC_STAT_ERR_OTHER 0xf9c70008 98 | 99 | #define TMIO_MASK_ALL 0x837f031d 100 | 101 | #define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ 102 | TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) 103 | 104 | #define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) 105 | #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) 106 | 107 | typedef struct mmcdevice { 108 | u8* rData; 109 | const u8* tData; 110 | u32 size; 111 | u32 startOffset; 112 | u32 endOffset; 113 | u32 error; 114 | u16 stat0; 115 | u16 stat1; 116 | u32 ret[4]; 117 | u32 initarg; 118 | u32 isSDHC; 119 | u32 clk; 120 | u32 SDOPT; 121 | u32 devicenumber; 122 | u32 total_size; //size in sectors of the device 123 | u32 res; 124 | } mmcdevice; 125 | 126 | enum { 127 | MMC_DEVICE_SDCARD, 128 | MMC_DEVICE_NAND, 129 | }; 130 | 131 | void sdmmc_controller_init(); 132 | void sdmmc_initirq(); 133 | int sdmmc_cardinserted(); 134 | 135 | int sdmmc_sdcard_init(); 136 | int sdmmc_nand_init(); 137 | void sdmmc_get_cid(int devicenumber, u32 *cid); 138 | 139 | static inline void sdmmc_nand_cid( u32 *cid) { 140 | sdmmc_get_cid(MMC_DEVICE_NAND,cid); 141 | } 142 | 143 | static inline void sdmmc_sdcard_cid( u32 *cid) { 144 | sdmmc_get_cid(MMC_DEVICE_SDCARD,cid); 145 | } 146 | 147 | int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out); 148 | int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, void *in); 149 | int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, void *out); 150 | int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, void *in); 151 | 152 | extern u32 sdmmc_cid[]; 153 | extern int sdmmc_curdevice; 154 | 155 | //--------------------------------------------------------------------------------- 156 | static inline u16 sdmmc_read16(u16 reg) { 157 | //--------------------------------------------------------------------------------- 158 | return *(vu16*)(SDMMC_BASE + reg); 159 | } 160 | 161 | //--------------------------------------------------------------------------------- 162 | static inline void sdmmc_write16(u16 reg, u16 val) { 163 | //--------------------------------------------------------------------------------- 164 | *(vu16*)(SDMMC_BASE + reg) = val; 165 | } 166 | 167 | //--------------------------------------------------------------------------------- 168 | static inline u32 sdmmc_read32(u16 reg) { 169 | //--------------------------------------------------------------------------------- 170 | return *(vu32*)(SDMMC_BASE + reg); 171 | } 172 | 173 | //--------------------------------------------------------------------------------- 174 | static inline void sdmmc_write32(u16 reg, u32 val) { 175 | //--------------------------------------------------------------------------------- 176 | *(vu32*)(SDMMC_BASE + reg) = val; 177 | } 178 | 179 | //--------------------------------------------------------------------------------- 180 | static inline void sdmmc_mask16(u16 reg, u16 clear, u16 set) { 181 | //--------------------------------------------------------------------------------- 182 | u16 val = sdmmc_read16(reg); 183 | val &= ~clear; 184 | val |= set; 185 | sdmmc_write16(reg, val); 186 | } 187 | 188 | 189 | //--------------------------------------------------------------------------------- 190 | static inline void setckl(u32 data) { 191 | //--------------------------------------------------------------------------------- 192 | sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); 193 | sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF); 194 | sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100); 195 | } 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /bootloader/source/boot.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | boot.c 3 | 4 | BootLoader 5 | Loads a file into memory and runs it 6 | 7 | All resetMemory and startBinary functions are based 8 | on the MultiNDS loader by Darkain. 9 | Original source available at: 10 | http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp 11 | 12 | License: 13 | Copyright (C) 2005 Michael "Chishm" Chisholm 14 | 15 | This program is free software; you can redistribute it and/or 16 | modify it under the terms of the GNU General Public License 17 | as published by the Free Software Foundation; either version 2 18 | of the License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | You should have received a copy of the GNU General Public License 26 | along with this program; if not, write to the Free Software 27 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 28 | 29 | If you use this code, please give due credit and email me about your 30 | project at chishm@hotmail.com 31 | 32 | Helpful information: 33 | This code runs from VRAM bank C on ARM7 34 | ------------------------------------------------------------------*/ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #define ARM9 42 | #undef ARM7 43 | #include 44 | #include 45 | #include 46 | #undef ARM9 47 | #define ARM7 48 | #include 49 | #include 50 | 51 | #include "sdmmc.h" 52 | #include "fat.h" 53 | #include "card.h" 54 | #include "boot.h" 55 | 56 | void mpu_reset(); 57 | void mpu_reset_end(); 58 | void arm7clearRAM(); 59 | 60 | //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 61 | // Important things 62 | #define TEMP_MEM 0x02FFD000 63 | #define NDS_HEAD 0x02FFFE00 64 | #define TEMP_ARM9_START_ADDRESS (*(vu32*)0x02FFFFF4) 65 | 66 | const char* bootName = "BOOTLOADER.NDS"; 67 | 68 | extern unsigned long _start; 69 | extern unsigned long storedFileCluster; 70 | extern unsigned long initDisc; 71 | extern unsigned long wantToPatchDLDI; 72 | extern unsigned long argStart; 73 | extern unsigned long argSize; 74 | extern unsigned long dsiSD; 75 | extern unsigned long dsiMode; 76 | 77 | /*------------------------------------------------------------------------- 78 | resetMemory_ARM7 79 | Clears all of the NDS's RAM that is visible to the ARM7 80 | Written by Darkain. 81 | Modified by Chishm: 82 | * Added STMIA clear mem loop 83 | --------------------------------------------------------------------------*/ 84 | void resetMemory_ARM7 (void) 85 | { 86 | int i; 87 | 88 | REG_IME = 0; 89 | 90 | for (i=0; i<16; i++) { 91 | SCHANNEL_CR(i) = 0; 92 | SCHANNEL_TIMER(i) = 0; 93 | SCHANNEL_SOURCE(i) = 0; 94 | SCHANNEL_LENGTH(i) = 0; 95 | } 96 | 97 | REG_SOUNDCNT = 0; 98 | 99 | //clear out ARM7 DMA channels and timers 100 | for (i=0; i<4; i++) { 101 | DMA_CR(i) = 0; 102 | DMA_SRC(i) = 0; 103 | DMA_DEST(i) = 0; 104 | TIMER_CR(i) = 0; 105 | TIMER_DATA(i) = 0; 106 | } 107 | 108 | arm7clearRAM(); 109 | 110 | REG_IE = 0; 111 | REG_IF = ~0; 112 | (*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version 113 | (*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version 114 | REG_POWERCNT = 1; //turn off power to stuff 115 | 116 | } 117 | 118 | 119 | void loadBinary_ARM7 (u32 fileCluster) 120 | { 121 | u32 ndsHeader[0x170>>2]; 122 | 123 | // read NDS header 124 | fileRead ((char*)ndsHeader, fileCluster, 0, 0x170); 125 | // read ARM9 info from NDS header 126 | u32 ARM9_SRC = ndsHeader[0x020>>2]; 127 | char* ARM9_DST = (char*)ndsHeader[0x028>>2]; 128 | u32 ARM9_LEN = ndsHeader[0x02C>>2]; 129 | // read ARM7 info from NDS header 130 | u32 ARM7_SRC = ndsHeader[0x030>>2]; 131 | char* ARM7_DST = (char*)ndsHeader[0x038>>2]; 132 | u32 ARM7_LEN = ndsHeader[0x03C>>2]; 133 | 134 | // Load binaries into memory 135 | fileRead(ARM9_DST, fileCluster, ARM9_SRC, ARM9_LEN); 136 | fileRead(ARM7_DST, fileCluster, ARM7_SRC, ARM7_LEN); 137 | 138 | // first copy the header to its proper location, excluding 139 | // the ARM9 start address, so as not to start it 140 | TEMP_ARM9_START_ADDRESS = ndsHeader[0x024>>2]; // Store for later 141 | ndsHeader[0x024>>2] = 0; 142 | dmaCopyWords(3, (void*)ndsHeader, (void*)NDS_HEAD, 0x170); 143 | 144 | } 145 | 146 | /*------------------------------------------------------------------------- 147 | startBinary_ARM7 148 | Jumps to the ARM7 NDS binary in sync with the display and ARM9 149 | Written by Darkain. 150 | Modified by Chishm: 151 | * Removed MultiNDS specific stuff 152 | --------------------------------------------------------------------------*/ 153 | void startBinary_ARM7 (void) { 154 | 155 | REG_IME=0; 156 | while(REG_VCOUNT!=191); 157 | while(REG_VCOUNT==191); 158 | // copy NDS ARM9 start address into the header, starting ARM9 159 | *((vu32*)0x02FFFE24) = TEMP_ARM9_START_ADDRESS; 160 | ARM9_START_FLAG = 1; 161 | 162 | // Start ARM7 163 | VoidFn arm7code = *(VoidFn*)(0x2FFFE34); 164 | arm7code(); 165 | } 166 | #ifndef NO_SDMMC 167 | int sdmmc_sd_readsectors(u32 sector_no, u32 numsectors, void *out); 168 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 169 | // Main function 170 | bool sdmmc_inserted() { 171 | return true; 172 | } 173 | 174 | bool sdmmc_startup() { 175 | sdmmc_controller_init(); 176 | return sdmmc_sdcard_init() == 0; 177 | } 178 | 179 | bool sdmmc_readsectors(u32 sector_no, u32 numsectors, void *out) { 180 | return sdmmc_sdcard_readsectors(sector_no, numsectors, out) == 0; 181 | } 182 | #endif 183 | 184 | int main (void) { 185 | #ifndef NO_SDMMC 186 | if (dsiSD) { 187 | _io_dldi.fn_readSectors = sdmmc_readsectors; 188 | _io_dldi.fn_isInserted = sdmmc_inserted; 189 | _io_dldi.fn_startup = sdmmc_startup; 190 | } 191 | #endif 192 | u32 fileCluster = storedFileCluster; 193 | // Init card 194 | if(!FAT_InitFiles(initDisc)) 195 | { 196 | return -1; 197 | } 198 | if (fileCluster == CLUSTER_FREE) 199 | { 200 | return -1; 201 | } 202 | 203 | // ARM9 clears its memory part 2 204 | // copy ARM9 function to RAM, and make the ARM9 jump to it 205 | memcpy((u32*)TEMP_MEM, (u32*)resetMemory2_ARM9, resetMemory2_ARM9_size); 206 | (*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function 207 | // Wait until the ARM9 has completed its task 208 | while ((*(vu32*)0x02FFFE24) == (u32)TEMP_MEM); 209 | 210 | // ARM9 sets up mpu 211 | // copy ARM9 function to RAM, and make the ARM9 jump to it 212 | memcpy((u32*)TEMP_MEM, (u32*)mpu_reset, mpu_reset_end - mpu_reset); 213 | (*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function 214 | // Wait until the ARM9 has completed its task 215 | while ((*(vu32*)0x02FFFE24) == (u32)TEMP_MEM); 216 | 217 | // ARM9 enters a wait loop 218 | // copy ARM9 function to RAM, and make the ARM9 jump to it 219 | memcpy((u32*)TEMP_MEM, (u32*)startBinary_ARM9, startBinary_ARM9_size); 220 | (*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function 221 | 222 | // Load the NDS file 223 | loadBinary_ARM7(fileCluster); 224 | 225 | // Reset SDMC. Required to get bootloader to init things correctly. 226 | sdmmc_controller_init(); 227 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFDu; 228 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDDu; 229 | *(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 0; 230 | 231 | startBinary_ARM7(); 232 | 233 | return 0; 234 | } 235 | 236 | -------------------------------------------------------------------------------- /arm9/source/gif.cpp: -------------------------------------------------------------------------------- 1 | #include "gif.hpp" 2 | #include "lzw.hpp" 3 | #include "tonccpy.h" 4 | 5 | #include 6 | 7 | std::vector Gif::_animating; 8 | 9 | void Gif::timerHandler(void) { 10 | for (auto gif : _animating) { 11 | gif->displayFrame(); 12 | } 13 | } 14 | 15 | void Gif::displayFrame(void) { 16 | if (_paused || ++_currentDelayProgress < _currentDelay) 17 | return; 18 | 19 | _currentDelayProgress = 0; 20 | _waitingForInput = false; 21 | 22 | if (_currentFrame >= _frames.size()) { 23 | _currentFrame = 0; 24 | _currentLoop++; 25 | } 26 | 27 | if (_currentLoop > _loopCount) { 28 | _finished = true; 29 | _paused = true; 30 | _currentLoop = 0; 31 | return; 32 | } 33 | 34 | Frame &frame = _frames[_currentFrame++]; 35 | 36 | if (frame.hasGCE) { 37 | _currentDelay = frame.gce.delay; 38 | if (frame.gce.delay == 0) { 39 | _finished = true; 40 | _paused = true; 41 | } else if (frame.gce.userInputFlag) { 42 | _waitingForInput = true; 43 | } 44 | } 45 | 46 | std::vector &colorTable = frame.descriptor.lctFlag ? frame.lct : _gct; 47 | 48 | tonccpy(_top ? BG_PALETTE : BG_PALETTE_SUB, colorTable.data(), colorTable.size() * 2); 49 | 50 | // Disposal method 2 = fill with bg color 51 | if (frame.gce.disposalMethod == 2) 52 | toncset(_top ? BG_GFX : BG_GFX_SUB, header.bgColor, 256 * 192); 53 | 54 | if(_compressed) { // Was left compressed to be able to fit 55 | int x = 0, y = 0; 56 | u8 *dst = (u8*)(_top ? BG_GFX : BG_GFX_SUB) + (frame.descriptor.y + y + (192 - header.height) / 2) * 256 + frame.descriptor.x + (256 - header.width) / 2; 57 | u8 row[frame.descriptor.w]; 58 | auto flush_fn = [&dst, &row, &x, &y, &frame](std::vector::const_iterator begin, std::vector::const_iterator end) { 59 | for (; begin != end; ++begin) { 60 | if (!frame.gce.transparentColorFlag || *begin != frame.gce.transparentColor) 61 | row[x] = *begin; 62 | else 63 | row[x] = *(dst + x); 64 | x++; 65 | if (x >= frame.descriptor.w) { 66 | tonccpy(dst, row, frame.descriptor.w); 67 | y++; 68 | x = 0; 69 | dst += 256; 70 | } 71 | } 72 | }; 73 | 74 | LZWReader reader(frame.image.lzwMinimumCodeSize, flush_fn); 75 | reader.decode(frame.image.imageData.begin(), frame.image.imageData.end()); 76 | } else { // Already decompressed, just copy 77 | auto it = frame.image.imageData.begin(); 78 | for(int y = 0; y < frame.descriptor.h; y++) { 79 | u8 *dst = (u8*)(_top ? BG_GFX : BG_GFX_SUB) + (frame.descriptor.y + y + (192 - header.height) / 2) * 256 + frame.descriptor.x + (256 - header.width) / 2; 80 | u8 row[frame.descriptor.w]; 81 | for(int x = 0; x < frame.descriptor.w; x++, it++) { 82 | if (!frame.gce.transparentColorFlag || *it != frame.gce.transparentColor) 83 | row[x] = *it; 84 | else 85 | row[x] = *(dst + x); 86 | } 87 | tonccpy(dst, row, frame.descriptor.w); 88 | } 89 | } 90 | } 91 | 92 | bool Gif::load(const char *path, bool top, bool animate, bool forceDecompress) { 93 | _top = top; 94 | 95 | FILE *file = fopen(path, "rb"); 96 | if (!file) 97 | return false; 98 | 99 | if(forceDecompress) { 100 | _compressed = false; 101 | } else { 102 | fseek(file, 0, SEEK_END); 103 | _compressed = ftell(file) > (/*dsiFeatures()*/true ? 1 << 20 : 1 << 18); // Decompress files bigger than 1MiB (256KiB in DS Mode) while drawing 104 | fseek(file, 0, SEEK_SET); 105 | } 106 | 107 | // Reserve space for 2,000 frames 108 | _frames.reserve(2000); 109 | 110 | // Read header 111 | fread(&header, 1, sizeof(header), file); 112 | 113 | // Check that this is a GIF 114 | if (memcmp(header.signature, "GIF87a", sizeof(header.signature)) != 0 && memcmp(header.signature, "GIF89a", sizeof(header.signature)) != 0) { 115 | fclose(file); 116 | return false; 117 | } 118 | 119 | // Load global color table 120 | if (header.gctFlag) { 121 | int numColors = (2 << header.gctSize); 122 | 123 | _gct = std::vector(numColors); 124 | for (int i = 0; i < numColors; i++) { 125 | const u8 r = fgetc(file); 126 | const u8 g = fgetc(file); 127 | const u8 b = fgetc(file); 128 | 129 | const u16 green = (g >> 2) << 5; 130 | _gct[i] = r >> 3 | (b >> 3) << 10; 131 | if (green & BIT(5)) { 132 | _gct[i] |= BIT(15); 133 | } 134 | for (int gBit = 6; gBit <= 10; gBit++) { 135 | if (green & BIT(gBit)) { 136 | _gct[i] |= BIT(gBit-1); 137 | } 138 | } 139 | } 140 | } 141 | 142 | // Set default loop count to 0, uninitialized default is 0xFFFF so it's infinite 143 | _loopCount = 0; 144 | 145 | Frame frame; 146 | while (1) { 147 | switch (fgetc(file)) { 148 | case 0x21: { // Extension 149 | switch (fgetc(file)) { 150 | case 0xF9: { // Graphics Control 151 | frame.hasGCE = true; 152 | fread(&frame.gce, 1, fgetc(file), file); 153 | if(frame.gce.delay < 2) // If delay is less then 2, change it to 10 154 | frame.gce.delay = 10; 155 | fgetc(file); // Terminator 156 | break; 157 | } case 0x01: { // Plain text 158 | // Unsupported for now, I can't even find a text GIF to test with 159 | // frame.hasText = true; 160 | // fread(&frame.textDescriptor, 1, sizeof(frame.textDescriptor), file); 161 | fseek(file, 12, SEEK_CUR); 162 | while (u8 size = fgetc(file)) { 163 | // char temp[size + 1]; 164 | // fread(temp, 1, size, file); 165 | // frame.text += temp; 166 | fseek(file, size, SEEK_CUR); 167 | } 168 | // _frames.push_back(frame); 169 | // frame = Frame(); 170 | break; 171 | } case 0xFF: { // Application extension 172 | if (fgetc(file) == 0xB) { 173 | char buffer[0xC] = {0}; 174 | fread(buffer, 1, 0xB, file); 175 | if (strcmp(buffer, "NETSCAPE2.0") == 0) { // Check for Netscape loop count 176 | fseek(file, 2, SEEK_CUR); 177 | fread(&_loopCount, 1, sizeof(_loopCount), file); 178 | if(_loopCount == 0) // If loop count 0 is specified, loop forever 179 | _loopCount = 0xFFFF; 180 | fgetc(file); //terminator 181 | break; 182 | } 183 | } 184 | } case 0xFE: { // Comment 185 | // Skip comments and unsupported application extionsions 186 | while (u8 size = fgetc(file)) { 187 | fseek(file, size, SEEK_CUR); 188 | } 189 | break; 190 | } 191 | } 192 | break; 193 | } case 0x2C: { // Image desriptor 194 | frame.hasImage = true; 195 | fread(&frame.descriptor, 1, sizeof(frame.descriptor), file); 196 | if (frame.descriptor.lctFlag) { 197 | int numColors = 2 << frame.descriptor.lctSize; 198 | frame.lct = std::vector(numColors); 199 | for (int i = 0; i < numColors; i++) { 200 | const u8 r = fgetc(file); 201 | const u8 g = fgetc(file); 202 | const u8 b = fgetc(file); 203 | 204 | const u16 green = (g >> 2) << 5; 205 | frame.lct[i] = r >> 3 | (b >> 3) << 10; 206 | if (green & BIT(5)) { 207 | frame.lct[i] |= BIT(15); 208 | } 209 | for (int gBit = 6; gBit <= 10; gBit++) { 210 | if (green & BIT(gBit)) { 211 | frame.lct[i] |= BIT(gBit-1); 212 | } 213 | } 214 | } 215 | } 216 | 217 | frame.image.lzwMinimumCodeSize = fgetc(file); 218 | if(_compressed) { // Leave compressed to fit more in RAM 219 | while (u8 size = fgetc(file)) { 220 | size_t end = frame.image.imageData.size(); 221 | frame.image.imageData.resize(end + size); 222 | fread(frame.image.imageData.data() + end, 1, size, file); 223 | } 224 | } else { // Decompress now for faster draw 225 | frame.image.imageData = std::vector(frame.descriptor.w * frame.descriptor.h); 226 | auto it = frame.image.imageData.begin(); 227 | auto flush_fn = [&it, &frame](std::vector::const_iterator begin, std::vector::const_iterator end) { 228 | std::copy(begin, end, it); 229 | it += std::distance(begin, end); 230 | }; 231 | LZWReader reader(frame.image.lzwMinimumCodeSize, flush_fn); 232 | 233 | while (u8 size = fgetc(file)) { 234 | std::vector buffer(size); 235 | fread(buffer.data(), 1, size, file); 236 | reader.decode(buffer.begin(), buffer.end()); 237 | } 238 | } 239 | 240 | _frames.push_back(frame); 241 | frame = Frame(); 242 | break; 243 | } case 0x3B: { // Trailer 244 | goto breakWhile; 245 | } 246 | } 247 | } 248 | breakWhile: 249 | 250 | fclose(file); 251 | 252 | _paused = false; 253 | _finished = loopForever(); 254 | _frames.shrink_to_fit(); 255 | if(animate) 256 | _animating.push_back(this); 257 | 258 | return true; 259 | } 260 | -------------------------------------------------------------------------------- /arm9/source/inifile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | inifile.cpp 3 | Copyright (C) 2007 Acekard, www.acekard.com 4 | Copyright (C) 2007-2009 somebody 5 | Copyright (C) 2009 yellow wood goblin 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include "inifile.h" 24 | #include "stringtool.h" 25 | 26 | static bool freadLine(FILE* f,std::string& str) 27 | { 28 | str.clear(); 29 | __read: 30 | char p=0; 31 | 32 | size_t readed=fread(&p,1,1,f); 33 | if(0==readed) 34 | { 35 | str=""; 36 | return false; 37 | } 38 | if('\n'==p||'\r'==p) 39 | { 40 | str=""; 41 | return true; 42 | } 43 | 44 | while(p!='\n'&&p!='\r'&&readed) 45 | { 46 | str+=p; 47 | readed=fread(&p,1,1,f); 48 | } 49 | 50 | if(str.empty()||""==str) 51 | { 52 | goto __read; 53 | } 54 | 55 | return true; 56 | } 57 | 58 | static void trimString(std::string& str) 59 | { 60 | size_t first=str.find_first_not_of(" \t"),last; 61 | if(first==str.npos) 62 | { 63 | str=""; 64 | } 65 | else 66 | { 67 | last=str.find_last_not_of(" \t"); 68 | if(first>0||(last+1)0) 91 | { 92 | m_FileContainer.clear(); 93 | } 94 | } 95 | 96 | void CIniFile::SetString(const std::string& Section,const std::string& Item,const std::string& Value) 97 | { 98 | if(GetFileString(Section,Item)!=Value) 99 | { 100 | SetFileString(Section,Item,Value); 101 | m_bModified=true; 102 | } 103 | } 104 | 105 | void CIniFile::SetInt(const std::string& Section,const std::string& Item,int Value) 106 | { 107 | std::string strtemp=formatString("%d",Value); 108 | 109 | if(GetFileString(Section,Item)!=strtemp) 110 | { 111 | SetFileString(Section,Item,strtemp); 112 | m_bModified=true; 113 | } 114 | } 115 | 116 | std::string CIniFile::GetString(const std::string& Section,const std::string& Item) 117 | { 118 | return GetFileString(Section,Item); 119 | } 120 | 121 | std::string CIniFile::GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue) 122 | { 123 | std::string temp=GetString(Section,Item); 124 | if(!m_bLastResult) 125 | { 126 | SetString(Section,Item,DefaultValue); 127 | temp=DefaultValue; 128 | } 129 | return temp; 130 | } 131 | 132 | void CIniFile::GetStringVector(const std::string& Section,const std::string& Item,std::vector< std::string >& strings,char delimiter) 133 | { 134 | std::string strValue=GetFileString(Section,Item); 135 | strings.clear(); 136 | size_t pos; 137 | while((pos=strValue.find(delimiter),strValue.npos!=pos)) 138 | { 139 | const std::string string=strValue.substr(0,pos); 140 | if(string.length()) 141 | { 142 | strings.push_back(string); 143 | } 144 | strValue=strValue.substr(pos+1,strValue.npos); 145 | } 146 | if(strValue.length()) 147 | { 148 | strings.push_back(strValue); 149 | } 150 | } 151 | 152 | void CIniFile::SetStringVector(const std::string& Section,const std::string& Item,std::vector& strings,char delimiter) 153 | { 154 | std::string strValue; 155 | for(size_t ii=0;ii2&&'0'==value[0]&&('x'==value[1]||'X'==value[1])) 167 | return strtol(value.c_str(),NULL,16); 168 | else 169 | return strtol(value.c_str(),NULL,10); 170 | } 171 | 172 | int CIniFile::GetInt(const std::string& Section,const std::string& Item,int DefaultValue) 173 | { 174 | int temp; 175 | temp=GetInt(Section,Item); 176 | if(!m_bLastResult) 177 | { 178 | SetInt(Section,Item,DefaultValue); 179 | temp=DefaultValue; 180 | } 181 | return temp; 182 | } 183 | 184 | bool CIniFile::LoadIniFile(const std::string& FileName) 185 | { 186 | //dbg_printf("load %s\n",FileName.c_str()); 187 | if(FileName!="") m_sFileName=FileName; 188 | 189 | FILE* f=fopen(FileName.c_str(),"rb"); 190 | 191 | if(NULL==f) return false; 192 | 193 | //check for utf8 bom. 194 | char bom[3]; 195 | if(fread(bom,3,1,f)==1&&bom[0]==0xef&&bom[1]==0xbb&&bom[2]==0xbf) ; 196 | else fseek(f,0,SEEK_SET); 197 | 198 | std::string strline(""); 199 | m_FileContainer.clear(); 200 | 201 | while(freadLine(f,strline)) 202 | { 203 | trimString(strline); 204 | if(strline!=""&&';'!=strline[0]&&'/'!=strline[0]&&'!'!=strline[0]) m_FileContainer.push_back(strline); 205 | } 206 | 207 | fclose(f); 208 | 209 | m_bLastResult=false; 210 | m_bModified=false; 211 | 212 | return true; 213 | } 214 | 215 | bool CIniFile::SaveIniFileModified(const std::string& FileName) 216 | { 217 | if(m_bModified==true) 218 | { 219 | return SaveIniFile(FileName); 220 | } 221 | 222 | return true; 223 | } 224 | 225 | bool CIniFile::SaveIniFile(const std::string& FileName) 226 | { 227 | if(FileName!="") 228 | m_sFileName=FileName; 229 | 230 | FILE* f=fopen(m_sFileName.c_str(),"wb"); 231 | if(NULL==f) 232 | { 233 | return false; 234 | } 235 | 236 | for(size_t ii=0;ii0) 242 | { 243 | if(!m_FileContainer[ii-1].empty()&&m_FileContainer[ii-1]!="") 244 | fwrite("\r\n",1,2,f); 245 | } 246 | if(!strline.empty()&&strline!="") 247 | { 248 | fwrite(strline.c_str(),1,strline.length(),f); 249 | fwrite("\r\n",1,2,f); 250 | } 251 | } 252 | 253 | fclose(f); 254 | 255 | m_bModified=false; 256 | 257 | return true; 258 | } 259 | 260 | std::string CIniFile::GetFileString(const std::string& Section,const std::string& Item) 261 | { 262 | std::string strline; 263 | std::string strSection; 264 | std::string strItem; 265 | std::string strValue; 266 | 267 | size_t ii=0; 268 | size_t iFileLines=m_FileContainer.size(); 269 | 270 | if(m_bReadOnly) 271 | { 272 | cSectionCache::iterator it=m_Cache.find(Section); 273 | if((it!=m_Cache.end())) ii=it->second; 274 | } 275 | 276 | m_bLastResult=false; 277 | 278 | if(iFileLines>=0) 279 | { 280 | while(ii0&&rBracketPos!=std::string::npos) 287 | { 288 | strSection=strline.substr(1,rBracketPos-1); 289 | if(m_bReadOnly) m_Cache.insert(std::make_pair(strSection,ii-1)); 290 | if(strSection==Section) 291 | { 292 | while(ii0&&rBracketPos!=std::string::npos) 342 | { 343 | strSection=strline.substr(1,rBracketPos-1); 344 | if(strSection==Section) 345 | { 346 | while(ii> 8 75 | crc_value = rotated ^ self.crc16_tab[(tmp & 0x00ff)] 76 | 77 | return crc_value 78 | except Exception as e: 79 | print("EXCEPTION(calculate): {}".format(e)) 80 | 81 | def init_crc16(self): 82 | """The algorithm uses tables with precalculated values""" 83 | for i in range(0, 256): 84 | crc = c_ushort(i).value 85 | for j in range(0, 8): 86 | if crc & 0x0001: 87 | crc = c_ushort(crc >> 1).value ^ self.crc16_constant 88 | else: 89 | crc = c_ushort(crc >> 1).value 90 | self.crc16_tab.append(crc) 91 | 92 | 93 | def getSize(fileobject): 94 | current = fileobject.tell() 95 | fileobject.seek(0, 2) # move the cursor to the end of the file 96 | size = fileobject.tell() 97 | fileobject.seek(current, 0) 98 | return size 99 | 100 | def skipUntilAddress(f_in, f_out, caddr, taddr): 101 | chunk = f_in.read(taddr - caddr) 102 | f_out.write(chunk) 103 | 104 | def writeBlankuntilAddress(f_out, caddr, taddr): 105 | f_out.write(b"\x00"*(taddr-caddr)) 106 | 107 | fname=args.file.name 108 | args.file.close() 109 | 110 | if not args.read: 111 | print("Patching file : "+fname) 112 | else: 113 | print("Reading header of file : "+fname) 114 | 115 | # offset of 0x4600 created 116 | 117 | # File size compute 118 | file = open(fname, 'rb') 119 | fsize=getSize(file) 120 | file.close() 121 | 122 | # CRC header compute "CRC-16 (Modbus)" 123 | file = open(fname, 'rb') 124 | # 0x15E from https://github.com/devkitPro/ndstool/ ... source/header.cpp 125 | hdr = file.read(0x15E) 126 | hdrCrc=CRC16(modbus_flag=True).calculate(hdr) 127 | if args.verbose: 128 | print("{:10s} {:20X}".format('HDR CRC-16 ModBus', hdrCrc)) 129 | # print("origin header cr c"+hdr[0x15E:0x15F]) 130 | # filew = open(fname+".hdr", "wb") 131 | # filew.write(hdr); 132 | # filew.close() 133 | file.close() 134 | 135 | if args.arm9 is not None: 136 | arm9Fname = args.arm9.name 137 | args.arm9.close() 138 | arm9File = open(arm9Fname, 'rb') 139 | arm9FileSize = getSize(arm9File) 140 | dataArm9 = arm9File.read(arm9FileSize) 141 | arm9File.close() 142 | 143 | if args.arm7 is not None: 144 | arm7Fname = args.arm7.name 145 | args.arm7.close() 146 | arm7File = open(arm7Fname, 'rb') 147 | arm7FileSize = getSize(arm7File) 148 | dataArm7 = arm7File.read(arm7FileSize) 149 | arm7File.close() 150 | 151 | filer = open(fname, 'rb') 152 | data = filer.read(0xB0) 153 | data += b'DoNotZeroFillMem' 154 | filer.read(0x10) 155 | data = data + filer.read(0xC0) 156 | caddr = 0x180 157 | 158 | # DS Data 180 bytes 159 | SrlHeader = namedtuple('SrlHeader', 160 | "gameTitle " 161 | "gameCode " 162 | "makerCode " 163 | "unitCode " 164 | "encryptionSeedSelect " 165 | "deviceCapacity " 166 | "reserved0 " 167 | "dsiflags " 168 | "romVersion " 169 | "internalFlag " 170 | "arm9RomOffset " 171 | "arm9EntryAddress " 172 | "arm9RamAddress " 173 | "arm9Size " 174 | "arm7RomOffset " 175 | "arm7EntryAddress " 176 | "arm7RamAddress " 177 | "arm7Size " 178 | "fntOffset " 179 | "fntSize " 180 | "fatOffset " 181 | "fatSize " 182 | "arm9OverlayOffset " 183 | "arm9OverlaySize " 184 | "arm7OverlayOffset " 185 | "arm7OverlaySize " 186 | "normalCardControlRegSettings " 187 | "secureCardControlRegSettings " 188 | "icon_bannerOffset " 189 | "secureAreaCrc " 190 | "secure_transfer_timeout " 191 | "arm9Autoload " 192 | "arm7Autoload " 193 | "secureDisable " 194 | "ntrRomSize " 195 | "headerSize " 196 | "reserved1 " 197 | "nintendoLogo " 198 | "nintendoLogoCrc " 199 | "headerCrc " 200 | "debugReserved ") 201 | srlHeaderFormat = '<12s4s2scbb7s2sbcIIIIIIIIIIIIIIIIIIIHHII8sII56s156s2sH32s' 202 | srlHeader = SrlHeader._make(unpack_from(srlHeaderFormat, data)) 203 | if args.verbose: 204 | print("origin header crc "+hex(srlHeader.headerCrc)) 205 | print("origin secure crc "+hex(srlHeader.secureAreaCrc)) 206 | 207 | # SecureArea CRC compute "CRC-16 (Modbus)" 208 | file = open(fname, 'rb') 209 | # 0x15E from https://github.com/devkitPro/ndstool/ ... source/header.cpp 210 | file.read(0x200) 211 | sec = file.read(0x4000) 212 | secCrc = CRC16(modbus_flag=True).calculate(sec) 213 | if args.verbose: 214 | print("{:10s} {:20X}".format('SEC CRC-16 ModBus', secCrc)) 215 | file.close() 216 | 217 | if srlHeader.arm7EntryAddress > 0x2400000 and not args.read and args.arm7 is None: 218 | print("WARNING: .nds arm7EntryAddress greater than 0x2400000 will not boot as cia") 219 | print("you need to recompile or swap the arm7 binary with a precompiled one with --arm7 and --arm7EntryAddress") 220 | 221 | if "dsi" in args.mode: 222 | srlHeaderPatched = srlHeader._replace( 223 | dsiflags= b'\x01\x00', # disable modcrypt but enable twl 224 | unitCode= b'\x03', 225 | ) 226 | 227 | data1 = pack(srlHeaderFormat, *srlHeaderPatched._asdict().values()) 228 | newHdrCrc = CRC16(modbus_flag = True).calculate(data1[0:0x15E]) 229 | srlHeaderPatched = srlHeaderPatched._replace(headerCrc = newHdrCrc) 230 | 231 | if args.verbose: 232 | print("new header crc "+hex(newHdrCrc)) 233 | if not args.read: 234 | if args.verbose: 235 | pprint(dict(srlHeaderPatched._asdict())) 236 | else: 237 | pprint(dict(srlHeader._asdict())) 238 | 239 | data1 = pack(srlHeaderFormat, *srlHeaderPatched._asdict().values()) 240 | 241 | arm9isize = 0 242 | arm7isize = 0 243 | 244 | # TWL Only Data 384 bytes 245 | SrlTwlExtHeader = namedtuple('SrlTwlExtHeader', 246 | "MBK_1_5_Settings " 247 | "MBK_6_8_Settings_ARM9 " 248 | "MBK_6_8_Settings_ARM7 " 249 | "global_MBK_9_Setting " 250 | "regionFlags " 251 | "accessControl " 252 | "arm7ScfgExtMask " 253 | "reserved_flags " 254 | "arm9iRomOffset " 255 | "reserved2 " 256 | "arm9iLoadAddress " 257 | "arm9iSize " 258 | "arm7iRomOffset " 259 | "struct_param_baseAddress " 260 | "arm7iLoadAddress " 261 | "arm7iSize " 262 | "digest_ntrRegionOffset " 263 | "digest_ntrRegionSize " 264 | "digest_twlRegionOffset " 265 | "digest_twlRegionSize " 266 | "digestSectorHashtableOffset " 267 | "digestSectorHashtableSize " 268 | "digest_blockHashtableOffset " 269 | "digest_blockHashtableSize " 270 | "digestSectorSize " 271 | "digest_blockSectorcount " 272 | "iconSize " #usually 0x23C0 or 2112 in homebrew 273 | "unknown1 " 274 | "twlRomSize " 275 | "unknown2 " 276 | "modcryptArea1Offset " 277 | "modcryptArea1Size " 278 | "modcryptArea2Offset " 279 | "modcryptArea2Size " 280 | "title_id " 281 | "pubSaveDataSize " 282 | "privSaveDataSize " 283 | "reserved4 " 284 | "parentalControl ") 285 | srlTwlExtHeaderFormat = "<20s12s12s4s4sIIII4sIIIIIIIIIIIIIIIII4sI12sIIII8sII176s16s" 286 | if srlHeader.headerSize < 0x300: 287 | # homebrew 288 | srlTwlExtHeader = SrlTwlExtHeader._make(unpack_from(srlTwlExtHeaderFormat, "\x00" * (0x300-0x180))) 289 | else: 290 | data = filer.read(0x300-0x180) 291 | srlTwlExtHeader = SrlTwlExtHeader._make(unpack_from(srlTwlExtHeaderFormat, data)) 292 | caddr = 0x300 293 | 294 | # pprint(dict(srlTwlExtHeader._asdict())) 295 | 296 | if not args.read: 297 | # Fix srlTwlExtHeader 298 | if "dsi" in args.mode: 299 | arm7iRomOffset = srlHeaderPatched.arm7RomOffset 300 | arm9iRomOffset = srlHeaderPatched.arm9RomOffset 301 | arm7isize = srlHeaderPatched.arm7Size 302 | arm9isize = srlHeaderPatched.arm9Size 303 | totaldsisize = 0 304 | arm7iname = None 305 | arm9iname = None 306 | 307 | if args.arm9i is not None: 308 | arm9iname = args.arm9i.name 309 | arm9isize = getSize(args.arm9i) 310 | arm9iRomOffset = srlHeaderPatched.ntrRomSize 311 | if args.verbose: 312 | print("arm9isize : "+hex(arm9isize)) 313 | print("arm9ioffset : "+hex(srlHeaderPatched.ntrRomSize)) 314 | args.arm9i.close() 315 | totaldsisize = arm9isize 316 | 317 | if args.arm7i is not None: 318 | arm7iname = args.arm7i.name 319 | arm7isize = getSize(args.arm7i) 320 | arm7iRomOffset = srlHeaderPatched.ntrRomSize+arm9isize 321 | if args.verbose: 322 | print("arm7isize : "+hex(arm7isize)) 323 | print("arm9ioffset : "+hex(srlHeaderPatched.ntrRomSize+arm9isize)) 324 | args.arm7i.close() 325 | totaldsisize = arm9isize + arm7isize 326 | 327 | 328 | 329 | srlTwlExtHeader = srlTwlExtHeader._replace( 330 | MBK_1_5_Settings= b"\x80\x84\x88\x8C\x81\x85\x89\x8D\x91\x95\x99\x9C\x81\x85\x89\x8D\x91\x95\x99\x9D", 331 | MBK_6_8_Settings_ARM9= b"\xC0\x37\x00\x08\x00\x30\xC0\x07\x00\x30\x00\x00", 332 | MBK_6_8_Settings_ARM7= b"\x00\x30\x00\x00\x00\x30\x40\x00\xB8\x37\xF8\x07", 333 | global_MBK_9_Setting= b"\x00\x00\x00\xFF", 334 | accessControl= 0x001FFEFF, 335 | arm7ScfgExtMask= 0x80040407, 336 | reserved_flags= 0x01000000 337 | ) 338 | 339 | if args.accessControl is not None: 340 | srlTwlExtHeader = srlTwlExtHeader._replace(accessControl=int(args.accessControl, 0)) 341 | 342 | if args.verbose or args.read: 343 | pprint(dict(srlTwlExtHeader._asdict())) 344 | 345 | data2=pack(srlTwlExtHeaderFormat, *srlTwlExtHeader._asdict().values()) 346 | 347 | if not args.read: 348 | # write the file 349 | if args.out is not None: 350 | filew = open(args.out, "wb") 351 | else: 352 | filew = open(fname + ".tmp", "wb") 353 | 354 | filew.write(data1) 355 | filew.write(data2) 356 | 357 | skipUntilAddress(filer, filew, caddr, srlTwlExtHeader.twlRomSize) 358 | 359 | filew.close() 360 | filer.close() 361 | 362 | if args.out is None: 363 | if os.path.exists(fname + ".orig.nds"): 364 | os.remove(fname + ".orig.nds") 365 | os.rename(fname, fname + ".orig.nds") 366 | os.rename(fname + ".tmp", fname) 367 | print("file patched") -------------------------------------------------------------------------------- /bootloader/source/sdmmc.c: -------------------------------------------------------------------------------- 1 | #ifndef NO_SDMMC 2 | #include 3 | #include "sdmmc.h" 4 | #include 5 | 6 | static struct mmcdevice deviceSD; 7 | 8 | //--------------------------------------------------------------------------------- 9 | int geterror(struct mmcdevice *ctx) { 10 | //--------------------------------------------------------------------------------- 11 | //if(ctx->error == 0x4) return -1; 12 | //else return 0; 13 | return (ctx->error << 29) >> 31; 14 | } 15 | 16 | 17 | //--------------------------------------------------------------------------------- 18 | void setTarget(struct mmcdevice *ctx) { 19 | //--------------------------------------------------------------------------------- 20 | sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber); 21 | setckl(ctx->clk); 22 | if (ctx->SDOPT == 0) { 23 | sdmmc_mask16(REG_SDOPT, 0, 0x8000); 24 | } else { 25 | sdmmc_mask16(REG_SDOPT, 0x8000, 0); 26 | } 27 | 28 | } 29 | 30 | 31 | //--------------------------------------------------------------------------------- 32 | void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) { 33 | //--------------------------------------------------------------------------------- 34 | const bool getSDRESP = (cmd << 15) >> 31; 35 | u16 flags = (cmd << 15) >> 31; 36 | const bool readdata = cmd & 0x20000; 37 | const bool writedata = cmd & 0x40000; 38 | 39 | if(readdata || writedata) 40 | { 41 | flags |= TMIO_STAT0_DATAEND; 42 | } 43 | 44 | ctx->error = 0; 45 | while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? 46 | sdmmc_write16(REG_SDIRMASK0,0); 47 | sdmmc_write16(REG_SDIRMASK1,0); 48 | sdmmc_write16(REG_SDSTATUS0,0); 49 | sdmmc_write16(REG_SDSTATUS1,0); 50 | sdmmc_mask16(REG_SDDATACTL32,0x1800,0x400); // Disable TX32RQ and RX32RDY IRQ. Clear fifo. 51 | sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); 52 | sdmmc_write16(REG_SDCMDARG1,args >> 16); 53 | sdmmc_write16(REG_SDCMD,cmd &0xFFFF); 54 | 55 | u32 size = ctx->size; 56 | const u16 blkSize = sdmmc_read16(REG_SDBLKLEN32); 57 | u32 *rDataPtr32 = (u32*)ctx->rData; 58 | u8 *rDataPtr8 = ctx->rData; 59 | const u32 *tDataPtr32 = (u32*)ctx->tData; 60 | const u8 *tDataPtr8 = ctx->tData; 61 | 62 | bool rUseBuf = ( NULL != rDataPtr32 ); 63 | bool tUseBuf = ( NULL != tDataPtr32 ); 64 | 65 | u16 status0 = 0; 66 | while(1) 67 | { 68 | volatile u16 status1 = sdmmc_read16(REG_SDSTATUS1); 69 | #ifdef DATA32_SUPPORT 70 | volatile u16 ctl32 = sdmmc_read16(REG_SDDATACTL32); 71 | if((ctl32 & 0x100)) 72 | #else 73 | if((status1 & TMIO_STAT1_RXRDY)) 74 | #endif 75 | { 76 | if(readdata) 77 | { 78 | if(rUseBuf) 79 | { 80 | sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); 81 | if(size >= blkSize) 82 | { 83 | #ifdef DATA32_SUPPORT 84 | if(!((u32)rDataPtr32 & 3)) 85 | { 86 | for(u32 i = 0; i < blkSize; i += 4) 87 | { 88 | *rDataPtr32++ = sdmmc_read32(REG_SDFIFO32); 89 | } 90 | } 91 | else 92 | { 93 | for(u32 i = 0; i < blkSize; i += 4) 94 | { 95 | u32 data = sdmmc_read32(REG_SDFIFO32); 96 | *rDataPtr8++ = data; 97 | *rDataPtr8++ = data >> 8; 98 | *rDataPtr8++ = data >> 16; 99 | *rDataPtr8++ = data >> 24; 100 | } 101 | } 102 | #else 103 | if(!((u32)rDataPtr16 & 1)) 104 | { 105 | for(u32 i = 0; i < blkSize; i += 4) 106 | { 107 | *rDataPtr16++ = sdmmc_read16(REG_SDFIFO); 108 | } 109 | } 110 | else 111 | { 112 | for(u32 i = 0; i < blkSize; i += 4) 113 | { 114 | u16 data = sdmmc_read16(REG_SDFIFO); 115 | *rDataPtr8++ = data; 116 | *rDataPtr8++ = data >> 8; 117 | } 118 | } 119 | #endif 120 | size -= blkSize; 121 | } 122 | } 123 | 124 | sdmmc_mask16(REG_SDDATACTL32, 0x800, 0); 125 | } 126 | } 127 | #ifdef DATA32_SUPPORT 128 | if(!(ctl32 & 0x200)) 129 | #else 130 | if((status1 & TMIO_STAT1_TXRQ)) 131 | #endif 132 | { 133 | if(writedata) 134 | { 135 | if(tUseBuf) 136 | { 137 | sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); 138 | if(size >= blkSize) 139 | { 140 | #ifdef DATA32_SUPPORT 141 | if(!((u32)tDataPtr32 & 3)) 142 | { 143 | for(u32 i = 0; i < blkSize; i += 4) 144 | { 145 | sdmmc_write32(REG_SDFIFO32, *tDataPtr32++); 146 | } 147 | } 148 | else 149 | { 150 | for(u32 i = 0; i < blkSize; i += 4) 151 | { 152 | u32 data = *tDataPtr8++; 153 | data |= (u32)*tDataPtr8++ << 8; 154 | data |= (u32)*tDataPtr8++ << 16; 155 | data |= (u32)*tDataPtr8++ << 24; 156 | sdmmc_write32(REG_SDFIFO32, data); 157 | } 158 | } 159 | #else 160 | if(!((u32)tDataPtr16 & 1)) 161 | { 162 | for(u32 i = 0; i < blkSize; i += 2) 163 | { 164 | sdmmc_write16(REG_SDFIFO, *tDataPtr16++); 165 | } 166 | } 167 | else 168 | { 169 | for(u32 i = 0; i < blkSize; i += 2) 170 | { 171 | u16 data = *tDataPtr8++; 172 | data |= (u16)(*tDataPtr8++ << 8); 173 | sdmmc_write16(REG_SDFIFO, data); 174 | } 175 | } 176 | #endif 177 | size -= blkSize; 178 | } 179 | } 180 | 181 | sdmmc_mask16(REG_SDDATACTL32, 0x1000, 0); 182 | } 183 | } 184 | if(status1 & TMIO_MASK_GW) 185 | { 186 | ctx->error |= 4; 187 | break; 188 | } 189 | 190 | if(!(status1 & TMIO_STAT1_CMD_BUSY)) 191 | { 192 | status0 = sdmmc_read16(REG_SDSTATUS0); 193 | if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) 194 | { 195 | ctx->error |= 0x1; 196 | } 197 | if(status0 & TMIO_STAT0_DATAEND) 198 | { 199 | ctx->error |= 0x2; 200 | } 201 | 202 | if((status0 & flags) == flags) 203 | break; 204 | } 205 | } 206 | ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); 207 | ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); 208 | sdmmc_write16(REG_SDSTATUS0,0); 209 | sdmmc_write16(REG_SDSTATUS1,0); 210 | 211 | if(getSDRESP != 0) 212 | { 213 | ctx->ret[0] = (u32)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16)); 214 | ctx->ret[1] = (u32)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16)); 215 | ctx->ret[2] = (u32)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16)); 216 | ctx->ret[3] = (u32)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16)); 217 | } 218 | } 219 | 220 | //--------------------------------------------------------------------------------- 221 | static u32 calcSDSize(u8* csd, int type) { 222 | //--------------------------------------------------------------------------------- 223 | u32 result = 0; 224 | if (type == -1) type = csd[14] >> 6; 225 | switch (type) { 226 | case 0: 227 | { 228 | u32 block_len = csd[9] & 0xf; 229 | block_len = 1 << block_len; 230 | u32 mult = (csd[4] >> 7) | ((csd[5] & 3) << 1); 231 | mult = 1 << (mult + 2); 232 | result = csd[8] & 3; 233 | result = (result << 8) | csd[7]; 234 | result = (result << 2) | (csd[6] >> 6); 235 | result = (result + 1) * mult * block_len / 512; 236 | } 237 | break; 238 | case 1: 239 | result = csd[7] & 0x3f; 240 | result = (result << 8) | csd[6]; 241 | result = (result << 8) | csd[5]; 242 | result = (result + 1) * 1024; 243 | break; 244 | } 245 | return result; 246 | } 247 | 248 | //--------------------------------------------------------------------------------- 249 | void sdmmc_controller_init() { 250 | //--------------------------------------------------------------------------------- 251 | deviceSD.isSDHC = 0; 252 | deviceSD.SDOPT = 0; 253 | deviceSD.res = 0; 254 | deviceSD.initarg = 0; 255 | deviceSD.clk = 0x80; 256 | deviceSD.devicenumber = 0; 257 | 258 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xF7FFu; 259 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xEFFFu; 260 | #ifdef DATA32_SUPPORT 261 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) |= 0x402u; 262 | #else 263 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) |= 0x402u; 264 | #endif 265 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL) = (*(vu16*)(SDMMC_BASE + REG_SDDATACTL) & 0xFFDD) | 2; 266 | #ifdef DATA32_SUPPORT 267 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFFu; 268 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDFu; 269 | *(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 512; 270 | #else 271 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFDu; 272 | *(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDDu; 273 | *(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 0; 274 | #endif 275 | *(vu16*)(SDMMC_BASE + REG_SDBLKCOUNT32) = 1; 276 | *(vu16*)(SDMMC_BASE + REG_SDRESET) &= 0xFFFEu; 277 | *(vu16*)(SDMMC_BASE + REG_SDRESET) |= 1u; 278 | *(vu16*)(SDMMC_BASE + REG_SDIRMASK0) |= TMIO_MASK_ALL; 279 | *(vu16*)(SDMMC_BASE + REG_SDIRMASK1) |= TMIO_MASK_ALL>>16; 280 | *(vu16*)(SDMMC_BASE + 0x0fc) |= 0xDBu; //SDCTL_RESERVED7 281 | *(vu16*)(SDMMC_BASE + 0x0fe) |= 0xDBu; //SDCTL_RESERVED8 282 | *(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu; 283 | #ifdef DATA32_SUPPORT 284 | *(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x20; 285 | *(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EE; 286 | #else 287 | *(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x40; //Nintendo sets this to 0x20 288 | *(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EB; //Nintendo sets this to 0x40EE 289 | #endif 290 | *(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu; 291 | *(vu16*)(SDMMC_BASE + REG_SDBLKLEN) = 512; 292 | *(vu16*)(SDMMC_BASE + REG_SDSTOP) = 0; 293 | 294 | setTarget(&deviceSD); 295 | } 296 | 297 | //--------------------------------------------------------------------------------- 298 | int sdmmc_sdcard_init() { 299 | //--------------------------------------------------------------------------------- 300 | // We need to send at least 74 clock pulses. 301 | setTarget(&deviceSD); 302 | swiDelay(0x1980); // ~75-76 clocks 303 | 304 | // card reset 305 | sdmmc_send_command(&deviceSD,0,0); 306 | 307 | // CMD8 0x1AA 308 | sdmmc_send_command(&deviceSD,0x10408,0x1AA); 309 | u32 temp = (deviceSD.error & 0x1) << 0x1E; 310 | 311 | u32 temp2 = 0; 312 | do { 313 | do { 314 | // CMD55 315 | sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); 316 | // ACMD41 317 | sdmmc_send_command(&deviceSD,0x10769,0x00FF8000 | temp); 318 | temp2 = 1; 319 | } while ( !(deviceSD.error & 1) ); 320 | 321 | } while((deviceSD.ret[0] & 0x80000000) == 0); 322 | 323 | if(!((deviceSD.ret[0] >> 30) & 1) || !temp) 324 | temp2 = 0; 325 | 326 | deviceSD.isSDHC = temp2; 327 | 328 | sdmmc_send_command(&deviceSD,0x10602,0); 329 | if (deviceSD.error & 0x4) return -1; 330 | 331 | sdmmc_send_command(&deviceSD,0x10403,0); 332 | if (deviceSD.error & 0x4) return -2; 333 | deviceSD.initarg = deviceSD.ret[0] >> 0x10; 334 | 335 | sdmmc_send_command(&deviceSD,0x10609,deviceSD.initarg << 0x10); 336 | if (deviceSD.error & 0x4) return -3; 337 | 338 | // Command Class 10 support 339 | const bool cmd6Supported = ((u8*)deviceSD.ret)[10] & 0x40; 340 | deviceSD.total_size = calcSDSize((u8*)&deviceSD.ret[0],-1); 341 | setckl(0x201); // 16.756991 MHz 342 | 343 | sdmmc_send_command(&deviceSD,0x10507,deviceSD.initarg << 0x10); 344 | if (deviceSD.error & 0x4) return -4; 345 | 346 | // CMD55 347 | sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); 348 | if (deviceSD.error & 0x4) return -5; 349 | 350 | // ACMD42 351 | sdmmc_send_command(&deviceSD,0x1076A,0x0); 352 | if (deviceSD.error & 0x4) return -6; 353 | 354 | // CMD55 355 | sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); 356 | if (deviceSD.error & 0x4) return -7; 357 | 358 | deviceSD.SDOPT = 1; 359 | sdmmc_send_command(&deviceSD,0x10446,0x2); 360 | if (deviceSD.error & 0x4) return -8; 361 | sdmmc_mask16(REG_SDOPT, 0x8000, 0); // Switch to 4 bit mode. 362 | 363 | // TODO: CMD6 to switch to high speed mode. 364 | if(cmd6Supported) 365 | { 366 | sdmmc_write16(REG_SDSTOP,0); 367 | sdmmc_write16(REG_SDBLKLEN32,64); 368 | sdmmc_write16(REG_SDBLKLEN,64); 369 | deviceSD.rData = NULL; 370 | deviceSD.size = 64; 371 | sdmmc_send_command(&deviceSD,0x31C06,0x80FFFFF1); 372 | sdmmc_write16(REG_SDBLKLEN,512); 373 | if(deviceSD.error & 0x4) return -9; 374 | 375 | deviceSD.clk = 0x200; // 33.513982 MHz 376 | setckl(0x200); 377 | } 378 | else deviceSD.clk = 0x201; // 16.756991 MHz 379 | 380 | sdmmc_send_command(&deviceSD,0x1040D,deviceSD.initarg << 0x10); 381 | if (deviceSD.error & 0x4) return -9; 382 | 383 | sdmmc_send_command(&deviceSD,0x10410,0x200); 384 | if (deviceSD.error & 0x4) return -10; 385 | 386 | return 0; 387 | 388 | } 389 | 390 | //--------------------------------------------------------------------------------- 391 | int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out) { 392 | //--------------------------------------------------------------------------------- 393 | if (deviceSD.isSDHC == 0) 394 | sector_no <<= 9; 395 | setTarget(&deviceSD); 396 | sdmmc_write16(REG_SDSTOP,0x100); 397 | 398 | #ifdef DATA32_SUPPORT 399 | sdmmc_write16(REG_SDBLKCOUNT32,numsectors); 400 | sdmmc_write16(REG_SDBLKLEN32,0x200); 401 | #endif 402 | 403 | sdmmc_write16(REG_SDBLKCOUNT,numsectors); 404 | deviceSD.rData = out; 405 | deviceSD.size = numsectors << 9; 406 | sdmmc_send_command(&deviceSD,0x33C12,sector_no); 407 | return geterror(&deviceSD); 408 | } 409 | #endif -------------------------------------------------------------------------------- /bootloader/source/fat.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------- 2 | fat.c 3 | 4 | NDS MP 5 | GBAMP NDS Firmware Hack Version 2.12 6 | An NDS aware firmware patch for the GBA Movie Player. 7 | By Michael Chisholm (Chishm) 8 | 9 | Filesystem code based on GBAMP_CF.c by Chishm (me). 10 | 11 | License: 12 | Copyright (C) 2005 Michael "Chishm" Chisholm 13 | 14 | This program is free software; you can redistribute it and/or 15 | modify it under the terms of the GNU General Public License 16 | as published by the Free Software Foundation; either version 2 17 | of the License, or (at your option) any later version. 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program; if not, write to the Free Software 26 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 27 | 28 | If you use this code, please give due credit and email me about your 29 | project at chishm@hotmail.com 30 | ------------------------------------------------------------------*/ 31 | 32 | #include "fat.h" 33 | #include "card.h" 34 | 35 | 36 | //--------------------------------------------------------------- 37 | // FAT constants 38 | 39 | #define FILE_LAST 0x00 40 | #define FILE_FREE 0xE5 41 | 42 | #define ATTRIB_ARCH 0x20 43 | #define ATTRIB_DIR 0x10 44 | #define ATTRIB_LFN 0x0F 45 | #define ATTRIB_VOL 0x08 46 | #define ATTRIB_HID 0x02 47 | #define ATTRIB_SYS 0x04 48 | #define ATTRIB_RO 0x01 49 | 50 | #define FAT16_ROOT_DIR_CLUSTER 0x00 51 | 52 | // File Constants 53 | #ifndef EOF 54 | #define EOF -1 55 | #define SEEK_SET 0 56 | #define SEEK_CUR 1 57 | #define SEEK_END 2 58 | #endif 59 | 60 | 61 | //----------------------------------------------------------------- 62 | // FAT constants 63 | #define CLUSTER_EOF_16 0xFFFF 64 | 65 | #define ATTRIB_ARCH 0x20 66 | #define ATTRIB_DIR 0x10 67 | #define ATTRIB_LFN 0x0F 68 | #define ATTRIB_VOL 0x08 69 | #define ATTRIB_HID 0x02 70 | #define ATTRIB_SYS 0x04 71 | #define ATTRIB_RO 0x01 72 | 73 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 74 | // Data Structures 75 | 76 | #define __PACKED __attribute__ ((__packed__)) 77 | 78 | // Boot Sector - must be packed 79 | typedef struct 80 | { 81 | u8 jmpBoot[3]; 82 | u8 OEMName[8]; 83 | // BIOS Parameter Block 84 | u16 bytesPerSector; 85 | u8 sectorsPerCluster; 86 | u16 reservedSectors; 87 | u8 numFATs; 88 | u16 rootEntries; 89 | u16 numSectorsSmall; 90 | u8 mediaDesc; 91 | u16 sectorsPerFAT; 92 | u16 sectorsPerTrk; 93 | u16 numHeads; 94 | u32 numHiddenSectors; 95 | u32 numSectors; 96 | union // Different types of extended BIOS Parameter Block for FAT16 and FAT32 97 | { 98 | struct 99 | { 100 | // Ext BIOS Parameter Block for FAT16 101 | u8 driveNumber; 102 | u8 reserved1; 103 | u8 extBootSig; 104 | u32 volumeID; 105 | u8 volumeLabel[11]; 106 | u8 fileSysType[8]; 107 | // Bootcode 108 | u8 bootCode[448]; 109 | } __PACKED fat16; 110 | struct 111 | { 112 | // FAT32 extended block 113 | u32 sectorsPerFAT32; 114 | u16 extFlags; 115 | u16 fsVer; 116 | u32 rootClus; 117 | u16 fsInfo; 118 | u16 bkBootSec; 119 | u8 reserved[12]; 120 | // Ext BIOS Parameter Block for FAT16 121 | u8 driveNumber; 122 | u8 reserved1; 123 | u8 extBootSig; 124 | u32 volumeID; 125 | u8 volumeLabel[11]; 126 | u8 fileSysType[8]; 127 | // Bootcode 128 | u8 bootCode[420]; 129 | } __PACKED fat32; 130 | } extBlock; 131 | 132 | __PACKED u16 bootSig; 133 | 134 | } __PACKED BOOT_SEC; 135 | 136 | // Directory entry - must be packed 137 | typedef struct 138 | { 139 | u8 name[8]; 140 | u8 ext[3]; 141 | u8 attrib; 142 | u8 reserved; 143 | u8 cTime_ms; 144 | u16 cTime; 145 | u16 cDate; 146 | u16 aDate; 147 | u16 startClusterHigh; 148 | u16 mTime; 149 | u16 mDate; 150 | u16 startCluster; 151 | u32 fileSize; 152 | } __PACKED DIR_ENT; 153 | 154 | // File information - no need to pack 155 | typedef struct 156 | { 157 | u32 firstCluster; 158 | u32 length; 159 | u32 curPos; 160 | u32 curClus; // Current cluster to read from 161 | int curSect; // Current sector within cluster 162 | int curByte; // Current byte within sector 163 | char readBuffer[512]; // Buffer used for unaligned reads 164 | u32 appClus; // Cluster to append to 165 | int appSect; // Sector within cluster for appending 166 | int appByte; // Byte within sector for appending 167 | bool read; // Can read from file 168 | bool write; // Can write to file 169 | bool append;// Can append to file 170 | bool inUse; // This file is open 171 | u32 dirEntSector; // The sector where the directory entry is stored 172 | int dirEntOffset; // The offset within the directory sector 173 | } FAT_FILE; 174 | 175 | 176 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 177 | // Global Variables 178 | 179 | // _VARS_IN_RAM variables are stored in the largest section of WRAM 180 | // available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA 181 | 182 | // Locations on card 183 | int discRootDir; 184 | int discRootDirClus; 185 | int discFAT; 186 | int discSecPerFAT; 187 | int discNumSec; 188 | int discData; 189 | int discBytePerSec; 190 | int discSecPerClus; 191 | int discBytePerClus; 192 | 193 | enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} discFileSystem; 194 | 195 | // Global sector buffer to save on stack space 196 | unsigned char globalBuffer[BYTES_PER_SECTOR]; 197 | 198 | 199 | //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 200 | //FAT routines 201 | 202 | u32 FAT_ClustToSect (u32 cluster) { 203 | return (((cluster-2) * discSecPerClus) + discData); 204 | } 205 | 206 | /*----------------------------------------------------------------- 207 | FAT_NextCluster 208 | Internal function - gets the cluster linked from input cluster 209 | -----------------------------------------------------------------*/ 210 | u32 FAT_NextCluster(u32 cluster) 211 | { 212 | u32 nextCluster = CLUSTER_FREE; 213 | u32 sector; 214 | int offset; 215 | 216 | 217 | switch (discFileSystem) 218 | { 219 | case FS_UNKNOWN: 220 | nextCluster = CLUSTER_FREE; 221 | break; 222 | 223 | case FS_FAT12: 224 | sector = discFAT + (((cluster * 3) / 2) / BYTES_PER_SECTOR); 225 | offset = ((cluster * 3) / 2) % BYTES_PER_SECTOR; 226 | CARD_ReadSector(sector, globalBuffer); 227 | nextCluster = ((u8*) globalBuffer)[offset]; 228 | offset++; 229 | 230 | if (offset >= BYTES_PER_SECTOR) { 231 | offset = 0; 232 | sector++; 233 | } 234 | 235 | CARD_ReadSector(sector, globalBuffer); 236 | nextCluster |= (((u8*) globalBuffer)[offset]) << 8; 237 | 238 | if (cluster & 0x01) { 239 | nextCluster = nextCluster >> 4; 240 | } else { 241 | nextCluster &= 0x0FFF; 242 | } 243 | 244 | break; 245 | 246 | case FS_FAT16: 247 | sector = discFAT + ((cluster << 1) / BYTES_PER_SECTOR); 248 | offset = cluster % (BYTES_PER_SECTOR >> 1); 249 | 250 | CARD_ReadSector(sector, globalBuffer); 251 | // read the nextCluster value 252 | nextCluster = ((u16*)globalBuffer)[offset]; 253 | 254 | if (nextCluster >= 0xFFF7) 255 | { 256 | nextCluster = CLUSTER_EOF; 257 | } 258 | break; 259 | 260 | case FS_FAT32: 261 | sector = discFAT + ((cluster << 2) / BYTES_PER_SECTOR); 262 | offset = cluster % (BYTES_PER_SECTOR >> 2); 263 | 264 | CARD_ReadSector(sector, globalBuffer); 265 | // read the nextCluster value 266 | nextCluster = (((u32*)globalBuffer)[offset]) & 0x0FFFFFFF; 267 | 268 | if (nextCluster >= 0x0FFFFFF7) 269 | { 270 | nextCluster = CLUSTER_EOF; 271 | } 272 | break; 273 | 274 | default: 275 | nextCluster = CLUSTER_FREE; 276 | break; 277 | } 278 | 279 | return nextCluster; 280 | } 281 | 282 | /*----------------------------------------------------------------- 283 | ucase 284 | Returns the uppercase version of the given char 285 | char IN: a character 286 | char return OUT: uppercase version of character 287 | -----------------------------------------------------------------*/ 288 | char ucase (char character) 289 | { 290 | if ((character > 0x60) && (character < 0x7B)) 291 | character = character - 0x20; 292 | return (character); 293 | } 294 | 295 | /*----------------------------------------------------------------- 296 | FAT_InitFiles 297 | Reads the FAT information from the CF card. 298 | You need to call this before reading any files. 299 | bool return OUT: true if successful. 300 | -----------------------------------------------------------------*/ 301 | bool FAT_InitFiles (bool initCard) 302 | { 303 | int i; 304 | int bootSector; 305 | BOOT_SEC* bootSec; 306 | 307 | if (initCard && !CARD_StartUp()) 308 | { 309 | return (false); 310 | } 311 | 312 | // Read first sector of card 313 | if (!CARD_ReadSector (0, globalBuffer)) 314 | { 315 | return false; 316 | } 317 | // Check if there is a FAT string, which indicates this is a boot sector 318 | if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T')) 319 | { 320 | bootSector = 0; 321 | } 322 | // Check for FAT32 323 | else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T')) 324 | { 325 | bootSector = 0; 326 | } 327 | else // This is an MBR 328 | { 329 | // Find first valid partition from MBR 330 | // First check for an active partition 331 | for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10); 332 | // If it didn't find an active partition, search for any valid partition 333 | if (i == 0x1FE) 334 | for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10); 335 | 336 | // Go to first valid partition 337 | if ( i != 0x1FE) // Make sure it found a partition 338 | { 339 | bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F); 340 | } else { 341 | bootSector = 0; // No partition found, assume this is a MBR free disk 342 | } 343 | } 344 | 345 | // Read in boot sector 346 | bootSec = (BOOT_SEC*) globalBuffer; 347 | CARD_ReadSector (bootSector, bootSec); 348 | 349 | // Store required information about the file system 350 | if (bootSec->sectorsPerFAT != 0) 351 | { 352 | discSecPerFAT = bootSec->sectorsPerFAT; 353 | } 354 | else 355 | { 356 | discSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32; 357 | } 358 | 359 | if (bootSec->numSectorsSmall != 0) 360 | { 361 | discNumSec = bootSec->numSectorsSmall; 362 | } 363 | else 364 | { 365 | discNumSec = bootSec->numSectors; 366 | } 367 | 368 | discBytePerSec = BYTES_PER_SECTOR; // Sector size is redefined to be 512 bytes 369 | discSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTES_PER_SECTOR; 370 | discBytePerClus = discBytePerSec * discSecPerClus; 371 | discFAT = bootSector + bootSec->reservedSectors; 372 | 373 | discRootDir = discFAT + (bootSec->numFATs * discSecPerFAT); 374 | discData = discRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / BYTES_PER_SECTOR); 375 | 376 | if ((discNumSec - discData) / bootSec->sectorsPerCluster < 4085) 377 | { 378 | discFileSystem = FS_FAT12; 379 | } 380 | else if ((discNumSec - discData) / bootSec->sectorsPerCluster < 65525) 381 | { 382 | discFileSystem = FS_FAT16; 383 | } 384 | else 385 | { 386 | discFileSystem = FS_FAT32; 387 | } 388 | 389 | if (discFileSystem != FS_FAT32) 390 | { 391 | discRootDirClus = FAT16_ROOT_DIR_CLUSTER; 392 | } 393 | else // Set up for the FAT32 way 394 | { 395 | discRootDirClus = bootSec->extBlock.fat32.rootClus; 396 | // Check if FAT mirroring is enabled 397 | if (!(bootSec->extBlock.fat32.extFlags & 0x80)) 398 | { 399 | // Use the active FAT 400 | discFAT = discFAT + ( discSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F)); 401 | } 402 | } 403 | 404 | return (true); 405 | } 406 | 407 | 408 | /*----------------------------------------------------------------- 409 | fileRead(buffer, cluster, startOffset, length) 410 | -----------------------------------------------------------------*/ 411 | u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length) 412 | { 413 | int curByte; 414 | int curSect; 415 | 416 | int dataPos = 0; 417 | int chunks; 418 | int beginBytes; 419 | 420 | if (cluster == CLUSTER_FREE || cluster == CLUSTER_EOF) 421 | { 422 | return 0; 423 | } 424 | 425 | // Follow cluster list until desired one is found 426 | for (chunks = startOffset / discBytePerClus; chunks > 0; chunks--) 427 | { 428 | cluster = FAT_NextCluster (cluster); 429 | } 430 | 431 | // Calculate the sector and byte of the current position, 432 | // and store them 433 | curSect = (startOffset % discBytePerClus) / BYTES_PER_SECTOR; 434 | curByte = startOffset % BYTES_PER_SECTOR; 435 | 436 | // Load sector buffer for new position in file 437 | CARD_ReadSector( curSect + FAT_ClustToSect(cluster), globalBuffer); 438 | curSect++; 439 | 440 | // Number of bytes needed to read to align with a sector 441 | beginBytes = (BYTES_PER_SECTOR < length + curByte ? (BYTES_PER_SECTOR - curByte) : length); 442 | 443 | // Read first part from buffer, to align with sector boundary 444 | for (dataPos = 0 ; dataPos < beginBytes; dataPos++) 445 | { 446 | buffer[dataPos] = globalBuffer[curByte++]; 447 | } 448 | 449 | // Read in all the 512 byte chunks of the file directly, saving time 450 | for ( chunks = ((int)length - beginBytes) / BYTES_PER_SECTOR; chunks > 0;) 451 | { 452 | int sectorsToRead; 453 | 454 | // Move to the next cluster if necessary 455 | if (curSect >= discSecPerClus) 456 | { 457 | curSect = 0; 458 | cluster = FAT_NextCluster (cluster); 459 | } 460 | 461 | // Calculate how many sectors to read (read a maximum of discSecPerClus at a time) 462 | sectorsToRead = discSecPerClus - curSect; 463 | if(chunks < sectorsToRead) 464 | sectorsToRead = chunks; 465 | 466 | // Read the sectors 467 | CARD_ReadSectors(curSect + FAT_ClustToSect(cluster), sectorsToRead, buffer + dataPos); 468 | chunks -= sectorsToRead; 469 | curSect += sectorsToRead; 470 | dataPos += BYTES_PER_SECTOR * sectorsToRead; 471 | } 472 | 473 | // Take care of any bytes left over before end of read 474 | if (dataPos < length) 475 | { 476 | 477 | // Update the read buffer 478 | curByte = 0; 479 | if (curSect >= discSecPerClus) 480 | { 481 | curSect = 0; 482 | cluster = FAT_NextCluster (cluster); 483 | } 484 | CARD_ReadSector( curSect + FAT_ClustToSect( cluster), globalBuffer); 485 | 486 | // Read in last partial chunk 487 | for (; dataPos < length; dataPos++) 488 | { 489 | buffer[dataPos] = globalBuffer[curByte]; 490 | curByte++; 491 | } 492 | } 493 | 494 | return dataPos; 495 | } 496 | -------------------------------------------------------------------------------- /arm9/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bios_decompress_callback.h" 8 | #include "fileOperations.h" 9 | #include "gif.hpp" 10 | #include "inifile.h" 11 | #include "nds_loader_arm9.h" 12 | #include "tonccpy.h" 13 | #include "version.h" 14 | 15 | #include "topLoad.h" 16 | #include "subLoad.h" 17 | // #include "topError.h" 18 | // #include "subError.h" 19 | 20 | #define CONSOLE_SCREEN_WIDTH 32 21 | #define CONSOLE_SCREEN_HEIGHT 24 22 | 23 | #define SETTINGS_INI_PATH "sd:/hiya/settings.ini" 24 | 25 | #define TMD_SIZE 0x208 26 | 27 | static char tmdBuffer[TMD_SIZE]; 28 | 29 | bool splash = true; 30 | bool dsiSplash = false; 31 | bool titleAutoboot = false; 32 | bool eraseUnlaunch = true; 33 | 34 | bool splashFound[2] = {false}; 35 | bool splashBmp[2] = {false}; 36 | bool rgb565BmpDisplayMode = false; 37 | u16* dsImageBuffer[2]; 38 | 39 | Gif gif[2]; 40 | 41 | void hBlankHandler() { 42 | int scanline = REG_VCOUNT; 43 | if (scanline > 192) { 44 | return; 45 | } else if (scanline == 192) { 46 | if (splashBmp[0]) { 47 | dmaCopyWordsAsynch(0, dsImageBuffer[0], BG_PALETTE_SUB, 256*2); 48 | } 49 | if (splashBmp[1]) { 50 | dmaCopyWordsAsynch(1, dsImageBuffer[1], BG_PALETTE, 256*2); 51 | } 52 | } else { 53 | scanline++; 54 | if (splashBmp[0]) { 55 | dmaCopyWordsAsynch(0, dsImageBuffer[0]+(scanline*256), BG_PALETTE_SUB, 256*2); 56 | } 57 | if (splashBmp[1]) { 58 | dmaCopyWordsAsynch(1, dsImageBuffer[1]+(scanline*256), BG_PALETTE, 256*2); 59 | } 60 | } 61 | } 62 | 63 | bool loadBMP(bool top) { 64 | FILE* file = fopen((top ? "sd:/hiya/splashtop.bmp" : "sd:/hiya/splashbottom.bmp"), "rb"); 65 | if (!file) 66 | return false; 67 | 68 | // Read width & height 69 | fseek(file, 0x12, SEEK_SET); 70 | u32 width, height; 71 | fread(&width, 1, sizeof(width), file); 72 | fread(&height, 1, sizeof(height), file); 73 | 74 | if (width > 256 || height > 192) { 75 | fclose(file); 76 | return false; 77 | } 78 | 79 | if (rgb565BmpDisplayMode) { 80 | dsImageBuffer[top] = new u16[256*192]; 81 | toncset(dsImageBuffer[top], 0, 256*192); 82 | } 83 | 84 | fseek(file, 0xE, SEEK_SET); 85 | u8 headerSize = fgetc(file); 86 | bool rgb565 = false; 87 | if(headerSize == 0x38) { 88 | // Check the upper byte green mask for if it's got 5 or 6 bits 89 | fseek(file, 0x2C, SEEK_CUR); 90 | rgb565 = fgetc(file) == 0x07; 91 | fseek(file, headerSize - 0x2E, SEEK_CUR); 92 | } else { 93 | fseek(file, headerSize - 1, SEEK_CUR); 94 | } 95 | u16 *bmpImageBuffer = new u16[width * height]; 96 | fread(bmpImageBuffer, 2, width * height, file); 97 | u16 *src = bmpImageBuffer; 98 | if (rgb565BmpDisplayMode) { 99 | u16 *dst = dsImageBuffer[top] + ((191 - ((192 - height) / 2)) * 256) + (256 - width) / 2; 100 | if (rgb565) { 101 | for (uint y = 0; y < height; y++, dst -= 256) { 102 | for (uint x = 0; x < width; x++) { 103 | u16 val = *(src++); 104 | const u16 green = ((val) & (0x3F << 5)); 105 | u16 color = ((val >> 11) & 0x1F) | (val & 0x1F) << 10; 106 | if (green & BIT(5)) { 107 | color |= BIT(15); 108 | } 109 | for (int g = 6; g <= 10; g++) { 110 | if (green & BIT(g)) { 111 | color |= BIT(g-1); 112 | } 113 | } 114 | *(dst + x) = color; 115 | } 116 | } 117 | } else { 118 | for (uint y = 0; y < height; y++, dst -= 256) { 119 | for (uint x = 0; x < width; x++) { 120 | u16 val = *(src++); 121 | *(dst + x) = ((val >> 10) & 0x1F) | ((val) & (0x1F << 5)) | (val & 0x1F) << 10; 122 | } 123 | } 124 | } 125 | } else { 126 | u16 *dst = (top ? BG_GFX : BG_GFX_SUB) + ((191 - ((192 - height) / 2)) * 256) + (256 - width) / 2; 127 | for (uint y = 0; y < height; y++, dst -= 256) { 128 | for (uint x = 0; x < width; x++) { 129 | u16 val = *(src++); 130 | *(dst + x) = ((val >> (rgb565 ? 11 : 10)) & 0x1F) | ((val >> (rgb565 ? 1 : 0)) & (0x1F << 5)) | (val & 0x1F) << 10 | BIT(15); 131 | } 132 | } 133 | } 134 | 135 | delete[] bmpImageBuffer; 136 | fclose(file); 137 | 138 | if (rgb565BmpDisplayMode) { 139 | u8* dsImageBuffer8 = new u8[256*192]; 140 | for (int i = 0; i < 256*192; i++) { 141 | dsImageBuffer8[i] = i; 142 | } 143 | 144 | dmaCopyWords(3, dsImageBuffer8, top ? BG_GFX : BG_GFX_SUB, 256*192); 145 | delete[] dsImageBuffer8; 146 | } 147 | return true; 148 | } 149 | 150 | void bootSplashInit() { 151 | // Initialize bitmap background 152 | videoSetMode(MODE_3_2D); 153 | videoSetModeSub(MODE_3_2D); 154 | vramSetBankA(VRAM_A_MAIN_BG); 155 | vramSetBankC(VRAM_C_SUB_BG); 156 | // Clear these to prevent messing up the main BG 157 | vramSetBankH(VRAM_H_LCD); 158 | vramSetBankG(VRAM_G_LCD); 159 | 160 | if (splashFound[true] && splashBmp[true] && !splashBmp[false]) 161 | bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0); 162 | else 163 | bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0); 164 | 165 | if (splashFound[false] && !splashBmp[true] && splashBmp[false]) 166 | bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0); 167 | else 168 | bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0); 169 | 170 | // Clear backgrounds 171 | toncset16(BG_PALETTE, 0, 256); 172 | toncset16(BG_PALETTE_SUB, 0, 256); 173 | toncset16(BG_GFX, 0, 256 * 256 * 2); 174 | toncset16(BG_GFX_SUB, 0, 256 * 256 * 2); 175 | } 176 | 177 | void loadScreen() { 178 | bootSplashInit(); 179 | 180 | rgb565BmpDisplayMode = ((!splashFound[true] || splashBmp[true]) && (!splashFound[false] || splashBmp[false])); 181 | 182 | // Display Load Screen 183 | if (splashBmp[true]) { 184 | loadBMP(true); 185 | } else if (!splashFound[true]) { 186 | tonccpy(BG_PALETTE, topLoadPal, topLoadPalLen); 187 | swiDecompressLZSSVram((void*)topLoadBitmap, BG_GFX, 0, &decompressBiosCallback); 188 | } 189 | if (splashBmp[false]) { 190 | loadBMP(false); 191 | } else if (!splashFound[false]) { 192 | tonccpy(BG_PALETTE_SUB, subLoadPal, subLoadPalLen); 193 | swiDecompressLZSSVram((void*)subLoadBitmap, BG_GFX_SUB, 0, &decompressBiosCallback); 194 | } 195 | 196 | if ((splashFound[true] || splashFound[false]) && rgb565BmpDisplayMode) { 197 | irqSet(IRQ_HBLANK, hBlankHandler); 198 | irqEnable(IRQ_HBLANK); 199 | } 200 | } 201 | 202 | int cursorPosition = 0; 203 | 204 | void loadSettings(void) { 205 | // GUI 206 | CIniFile settingsini(SETTINGS_INI_PATH); 207 | 208 | splash = settingsini.GetInt("HIYA-CFW", "SPLASH", 0); 209 | dsiSplash = settingsini.GetInt("HIYA-CFW", "DSI_SPLASH", 0); 210 | titleAutoboot = settingsini.GetInt("HIYA-CFW", "TITLE_AUTOBOOT", 0); 211 | eraseUnlaunch = settingsini.GetInt("HIYA-CFW", "ERASE_UNLAUNCH", 1); 212 | } 213 | 214 | void saveSettings(void) { 215 | // GUI 216 | CIniFile settingsini(SETTINGS_INI_PATH); 217 | 218 | settingsini.SetInt("HIYA-CFW", "SPLASH", splash); 219 | settingsini.SetInt("HIYA-CFW", "DSI_SPLASH", dsiSplash); 220 | settingsini.SetInt("HIYA-CFW", "TITLE_AUTOBOOT", titleAutoboot); 221 | settingsini.SaveIniFile(SETTINGS_INI_PATH); 222 | } 223 | 224 | void setupConsole() { 225 | // Subscreen as a console 226 | videoSetMode(MODE_0_2D); 227 | vramSetBankG(VRAM_G_MAIN_BG); 228 | videoSetModeSub(MODE_0_2D); 229 | vramSetBankH(VRAM_H_SUB_BG); 230 | } 231 | 232 | int main( int argc, char **argv) { 233 | extern void dsiOnly(void); 234 | dsiOnly(); 235 | 236 | // defaultExceptionHandler(); 237 | 238 | /* scanKeys(); 239 | if ((keysHeld() & KEY_RIGHT) && (keysHeld() & KEY_A)) { 240 | setupConsole(); 241 | 242 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 243 | consoleClear(); 244 | 245 | iprintf("Please remove the SD Card and\n"); 246 | iprintf("insert the SD Card containing\n"); 247 | iprintf("hiyaCFW, then press A\n"); 248 | iprintf("to continue."); 249 | 250 | // Prevent accidential presses 251 | for (int i = 0; i < 60; i++) { 252 | swiWaitForVBlank(); 253 | } 254 | 255 | while (1) { 256 | scanKeys(); 257 | if (keysHeld() & KEY_A) break; 258 | swiWaitForVBlank(); 259 | } 260 | 261 | for (int i = 0; i < 24; i++) { 262 | swiWaitForVBlank(); 263 | } 264 | } 265 | 266 | *(u32*)0x0CFFFD0C = 0x54534453; // 'SDST' 267 | while (*(u32*)0x0CFFFD0C != 0) { swiDelay(100); } */ 268 | 269 | u32 sdIrqStatus = fifoGetValue32(FIFO_USER_01); 270 | if ((sdIrqStatus & BIT(5)) != 0 && (sdIrqStatus & BIT(7)) == 0) { 271 | setupConsole(); 272 | 273 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 274 | consoleClear(); 275 | 276 | iprintf("The SD card is write-locked.\n"); 277 | iprintf("Please turn off the POWER,\n"); 278 | iprintf("remove the SD card, move the\n"); 279 | iprintf("write-lock switch up, re-insert\n"); 280 | iprintf("the SD card, then try again."); 281 | 282 | while (1) 283 | swiWaitForVBlank(); 284 | } 285 | 286 | if (!fatInitDefault()) { 287 | /* bootSplashInit(); 288 | 289 | // Display Error Screen 290 | swiDecompressLZSSVram((void*)topErrorBitmap, BG_GFX, 0, &decompressBiosCallback); 291 | swiDecompressLZSSVram((void*)subErrorBitmap, BG_GFX_SUB, 0, &decompressBiosCallback); 292 | tonccpy(&BG_PALETTE[0], topErrorPal, topErrorPalLen); 293 | tonccpy(&BG_PALETTE_SUB[0], subErrorPal, subErrorPalLen); */ 294 | 295 | setupConsole(); 296 | 297 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 298 | consoleClear(); 299 | 300 | iprintf("FAT init failed!"); 301 | 302 | while (1) 303 | swiWaitForVBlank(); 304 | } 305 | 306 | if ((access("sd:/", F_OK) != 0) && (access("fat:/", F_OK) == 0)) { 307 | setupConsole(); 308 | 309 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 310 | consoleClear(); 311 | 312 | iprintf("hiyaCFW is not compatible\n"); 313 | iprintf("with flashcards!"); 314 | 315 | while (1) 316 | swiWaitForVBlank(); 317 | } 318 | 319 | u8 oldRegion = 0; 320 | u8 regionChar = 0; 321 | FILE* f_hwinfoS = fopen("sd:/sys/HWINFO_S.dat", "rb"); 322 | if (f_hwinfoS) { 323 | fseek(f_hwinfoS, 0x90, SEEK_SET); 324 | fread(&oldRegion, 1, 1, f_hwinfoS); 325 | fseek(f_hwinfoS, 0xA0, SEEK_SET); 326 | fread(®ionChar, 1, 1, f_hwinfoS); 327 | fclose(f_hwinfoS); 328 | } else { 329 | setupConsole(); 330 | consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); 331 | consoleClear(); 332 | iprintf("Error!\n"); 333 | iprintf("\n"); 334 | iprintf("HWINFO_S.dat not found!"); 335 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 336 | consoleClear(); 337 | 338 | while (1) 339 | swiWaitForVBlank(); 340 | } 341 | 342 | u8 newRegion = oldRegion; 343 | if (regionChar == 'C') { 344 | if (newRegion != 4) newRegion = 4; 345 | } else if (regionChar == 'K') { 346 | if (newRegion != 5) newRegion = 5; 347 | } else { 348 | if (newRegion >= 4) newRegion = 0; 349 | } 350 | 351 | loadSettings(); 352 | 353 | bool gotoSettings = (access(SETTINGS_INI_PATH, F_OK) != 0); 354 | 355 | scanKeys(); 356 | 357 | if (keysHeld() & KEY_SELECT) gotoSettings = true; 358 | 359 | if (gotoSettings) { 360 | setupConsole(); 361 | 362 | int optionCount = 2; 363 | int optionShift = 0; 364 | if (regionChar != 'C' && regionChar != 'K') { 365 | optionCount++; // Display region setting 366 | optionShift++; 367 | } 368 | 369 | int pressed = 0; 370 | bool menuprinted = true; 371 | 372 | while (1) { 373 | if (menuprinted) { 374 | consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); 375 | consoleClear(); 376 | 377 | iprintf ("\x1B[46m"); 378 | 379 | iprintf("hiyaCFW %s%cconfiguration\n", VER_NUMBER, sizeof(VER_NUMBER) > 11 ? '\n' : ' '); 380 | iprintf("Press A to select, START to save"); 381 | iprintf("\n"); 382 | 383 | iprintf ("\x1B[47m"); 384 | 385 | if (optionCount > 2) { 386 | if (cursorPosition == 0) iprintf ("\x1B[41m"); 387 | else iprintf ("\x1B[47m"); 388 | 389 | iprintf(" Region: "); 390 | switch (newRegion) { 391 | case 0: 392 | iprintf("JPN(x), USA( ),\n EUR( ), AUS( )"); 393 | break; 394 | case 1: 395 | iprintf("JPN( ), USA(x),\n EUR( ), AUS( )"); 396 | break; 397 | case 2: 398 | iprintf("JPN( ), USA( ),\n EUR(x), AUS( )"); 399 | break; 400 | case 3: 401 | iprintf("JPN( ), USA( ),\n EUR( ), AUS(x)"); 402 | break; 403 | } 404 | iprintf("\n\n"); 405 | } 406 | 407 | if (cursorPosition == 0+optionShift) iprintf ("\x1B[41m"); 408 | else iprintf ("\x1B[47m"); 409 | 410 | iprintf(" Splash: "); 411 | if (splash) 412 | iprintf("Off( ), On(x)"); 413 | else 414 | iprintf("Off(x), On( )"); 415 | iprintf("\n\n"); 416 | 417 | if (cursorPosition == 1+optionShift) iprintf ("\x1B[41m"); 418 | else iprintf ("\x1B[47m"); 419 | 420 | if (dsiSplash) 421 | iprintf(" (x)"); 422 | else 423 | iprintf(" ( )"); 424 | iprintf(" DSi Splash/H&S screen\n"); 425 | 426 | if (cursorPosition == 2+optionShift) iprintf ("\x1B[41m"); 427 | else iprintf ("\x1B[47m"); 428 | 429 | if (titleAutoboot) 430 | iprintf(" (x)"); 431 | else 432 | iprintf(" ( )"); 433 | iprintf(" Autoboot title\n"); 434 | 435 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 436 | consoleClear(); 437 | 438 | iprintf("\n"); 439 | if ((cursorPosition == 0) && (optionCount > 2)) { 440 | iprintf(" Change the SDNAND region.\n"); 441 | iprintf(" \n"); 442 | iprintf(" Changing from the original\n"); 443 | iprintf(" will break apps such as DSi\n"); 444 | iprintf(" Shop and 3DS Transfer Tool.\n"); 445 | if (regionChar == 'J') { 446 | iprintf(" \n"); 447 | iprintf(" System settings will be reset.\n"); 448 | } 449 | iprintf(" \n"); 450 | iprintf(" Original region: "); 451 | if (regionChar == 'J') { 452 | iprintf("JPN"); 453 | } else if (regionChar == 'E') { 454 | iprintf("USA"); 455 | } else if (regionChar == 'P') { 456 | iprintf("EUR"); 457 | } else if (regionChar == 'U') { 458 | iprintf("AUS"); 459 | } 460 | } else if (cursorPosition == 0+optionShift) { 461 | iprintf(" Enable splash screen."); 462 | } else if (cursorPosition == 1+optionShift) { 463 | iprintf(" Enable showing the DSi Splash/\n"); 464 | iprintf(" Health & Safety screen."); 465 | } else if (cursorPosition == 2+optionShift) { 466 | iprintf(" Load title contained in\n"); 467 | iprintf(" sd:/hiya/autoboot.bin\n"); 468 | iprintf(" instead of the DSi Menu."); 469 | } 470 | 471 | menuprinted = false; 472 | } 473 | 474 | do { 475 | scanKeys(); 476 | pressed = keysDownRepeat(); 477 | swiWaitForVBlank(); 478 | } while (!pressed); 479 | 480 | if (pressed & KEY_L) { 481 | // Debug code 482 | FILE* ResetData = fopen("sd:/hiya/ResetData_extract.bin","wb"); 483 | fwrite((void*)0x02000000,1,0x800,ResetData); 484 | fclose(ResetData); 485 | for (int i = 0; i < 30; i++) swiWaitForVBlank(); 486 | } 487 | 488 | if (pressed & KEY_A) { 489 | if (optionCount > 2) { 490 | switch (cursorPosition){ 491 | case 0: 492 | newRegion++; 493 | if (newRegion == 4) newRegion = 0; 494 | break; 495 | case 1: 496 | default: 497 | splash = !splash; 498 | break; 499 | case 2: 500 | dsiSplash = !dsiSplash; 501 | break; 502 | case 3: 503 | titleAutoboot = !titleAutoboot; 504 | break; 505 | } 506 | } else { 507 | switch (cursorPosition){ 508 | case 0: 509 | default: 510 | splash = !splash; 511 | break; 512 | case 1: 513 | dsiSplash = !dsiSplash; 514 | break; 515 | case 2: 516 | titleAutoboot = !titleAutoboot; 517 | break; 518 | } 519 | } 520 | menuprinted = true; 521 | } 522 | 523 | if (pressed & KEY_UP) { 524 | cursorPosition--; 525 | menuprinted = true; 526 | } else if (pressed & KEY_DOWN) { 527 | cursorPosition++; 528 | menuprinted = true; 529 | } 530 | 531 | if (cursorPosition < 0) cursorPosition = optionCount; 532 | if (cursorPosition > optionCount) cursorPosition = 0; 533 | 534 | if (pressed & KEY_START) { 535 | saveSettings(); 536 | break; 537 | } 538 | } 539 | } 540 | 541 | if (newRegion != oldRegion) { 542 | FILE* f_hwinfoS = fopen("sd:/sys/HWINFO_S.dat", "rb+"); 543 | if (f_hwinfoS) { 544 | u32 supportedLangBitmask = 0x01; // JPN: Japanese 545 | if (newRegion == 5) { // KOR 546 | supportedLangBitmask = 0x80; // Korean 547 | } else if (newRegion == 4) { // CHN 548 | supportedLangBitmask = 0x40; // Chinese 549 | } else if (newRegion == 3) { // AUS 550 | supportedLangBitmask = 0x02; // English 551 | } else if (newRegion == 2) { // EUR 552 | supportedLangBitmask = 0x3E; // English, French, German, Italian, Spanish 553 | } else if (newRegion == 1) { // USA 554 | supportedLangBitmask = 0x26; // English, French, Spanish 555 | } 556 | fseek(f_hwinfoS, 0x88, SEEK_SET); 557 | fwrite(&supportedLangBitmask, sizeof(u32), 1, f_hwinfoS); 558 | fseek(f_hwinfoS, 0x90, SEEK_SET); 559 | fwrite(&newRegion, 1, 1, f_hwinfoS); 560 | fclose(f_hwinfoS); 561 | if (regionChar == 'J') { 562 | // Reset system settings to work around touch inputs not working 563 | remove("sd:/shared1/TWLCFG0.dat"); 564 | remove("sd:/shared1/TWLCFG1.dat"); 565 | } 566 | } 567 | } 568 | 569 | // Create dummy file 570 | // Check the free space 571 | struct statvfs st; 572 | statvfs("sd:/", &st); 573 | u32 freeSpace = st.f_bsize * st.f_bfree; 574 | u64 realFreeSpace = st.f_bsize * st.f_bfree; 575 | 576 | // If the free space is bigger than 2GiB (using a u32 so always 0 - 4GiB) 577 | // or the free space is less than 20MiB (and the actual free space is over 4GiB) 578 | if(freeSpace > (2u << 30) || (freeSpace < (20u << 20) && realFreeSpace > (4u << 30))) { 579 | consoleDemoInit(); 580 | size_t oldSize = 0; 581 | // Check old dummy file size to see if it can just be removed 582 | FILE *file = fopen("sd:/hiya/dummy.bin", "rb"); 583 | if(file) { 584 | fseek(file, 0, SEEK_END); 585 | oldSize = ftell(file); 586 | fclose(file); 587 | } 588 | 589 | // Check that dummy file is still needed 590 | if((freeSpace + oldSize) > (2u << 30) || (freeSpace + oldSize) < (20u << 20)) { 591 | // Make sure hiya directory exists and make the file 592 | mkdir("sd:/hiya", 0777); 593 | iprintf("Making new dummy file... "); 594 | 595 | // Make sure the file exists 596 | file = fopen("sd:/hiya/dummy.bin", "wb"); 597 | if(file) 598 | fclose(file); 599 | 600 | // If free space is less than 20MiB, add free space + 2GiB + 10MiB 601 | // otherwise add free space - 2GiB + 10MiB 602 | truncate("sd:/hiya/dummy.bin", (freeSpace < (20u << 20) ? (freeSpace + (2 << 30)) : (freeSpace - (2 << 30))) + (10 << 20)); 603 | iprintf("Done!\n"); 604 | } else { 605 | iprintf("Removing old dummy file... "); 606 | remove("sd:/hiya/dummy.bin"); 607 | iprintf("Done!\n"); 608 | } 609 | } 610 | 611 | if (!gotoSettings && (*(u32*)0x02000300 == 0x434E4C54 || fifoGetValue32(FIFO_USER_02) == 0x01)) { 612 | // if "CNLT" is found in RAM, or if warmboot flag is set, then don't show splash 613 | splash = false; 614 | } 615 | 616 | if ((*(u32*)0x02000300 == 0x434E4C54) && (*(u32*)0x02000310 != 0x00000000)) { 617 | // if "CNLT" is found, and a title is set to launch, then don't autoboot title in "autoboot.bin" 618 | titleAutoboot = false; 619 | } 620 | 621 | if (titleAutoboot) { 622 | FILE* ResetData = fopen("sd:/hiya/autoboot.bin","rb"); 623 | if (ResetData) { 624 | fread((void*)0x02000300,1,0x20,ResetData); 625 | dsiSplash = false; // Disable DSi splash, so that DSi Menu doesn't appear 626 | fclose(ResetData); 627 | } 628 | } 629 | 630 | if (splash) { 631 | if (gif[true].load("sd:/hiya/splashtop.gif", true, true, false)) { 632 | splashFound[true] = true; 633 | splashBmp[true] = false; 634 | } else if (access("sd:/hiya/splashtop.bmp", F_OK) == 0) { 635 | splashFound[true] = true; 636 | splashBmp[true] = true; 637 | } 638 | 639 | if (gif[false].load("sd:/hiya/splashbottom.gif", false, true, false)) { 640 | splashFound[false] = true; 641 | splashBmp[false] = false; 642 | } else if (access("sd:/hiya/splashtop.bmp", F_OK) == 0) { 643 | splashFound[false] = true; 644 | splashBmp[false] = true; 645 | } 646 | 647 | loadScreen(); 648 | 649 | if (rgb565BmpDisplayMode) { 650 | for (int i = 0; i < 60 * 3; i++) 651 | swiWaitForVBlank(); 652 | } else { 653 | timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(100), Gif::timerHandler); 654 | 655 | // If both GIFs will loop forever (or are not loaded) 656 | // then show for 3s 657 | if (gif[true].loopForever() && gif[false].loopForever()) { 658 | for (int i = 0; i < 60 * 3; i++) 659 | swiWaitForVBlank(); 660 | } else { 661 | while (!(gif[true].finished() && gif[false].finished())) { 662 | swiWaitForVBlank(); 663 | scanKeys(); 664 | u16 down = keysDown(); 665 | 666 | for (auto &g : gif) { 667 | if (g.waitingForInput() && down) 668 | g.resume(); 669 | } 670 | } 671 | } 672 | timerStop(0); 673 | } 674 | } 675 | 676 | if (!dsiSplash) { 677 | fifoSendValue32(FIFO_USER_03, 1); 678 | // Tell Arm7 to check FIFO_USER_03 code 679 | fifoSendValue32(FIFO_USER_04, 1); 680 | // Small delay to ensure arm7 has time to write i2c stuff 681 | for (int i = 0; i < 1*3; i++) { swiWaitForVBlank(); } 682 | } else { 683 | fifoSendValue32(FIFO_USER_04, 1); 684 | } 685 | 686 | char tmdpath[256]; 687 | snprintf (tmdpath, sizeof(tmdpath), "sd:/title/00030017/484e41%x/content/title.tmd", regionChar); 688 | 689 | FILE* f_tmd = fopen(tmdpath, "rb"); 690 | if (f_tmd) { 691 | if ((getFileSize(tmdpath) > TMD_SIZE) && eraseUnlaunch) { 692 | // Read big .tmd file at the correct size 693 | f_tmd = fopen(tmdpath, "rb"); 694 | fread(tmdBuffer, 1, TMD_SIZE, f_tmd); 695 | fclose(f_tmd); 696 | 697 | // Write correct sized .tmd file 698 | f_tmd = fopen(tmdpath, "wb"); 699 | fwrite(tmdBuffer, 1, TMD_SIZE, f_tmd); 700 | fclose(f_tmd); 701 | } 702 | int err = runNdsFile("sd:/hiya/BOOTLOADER.NDS", 0, NULL); 703 | if ((splashFound[true] || splashFound[false]) && rgb565BmpDisplayMode) { 704 | while (dmaBusy(0) || dmaBusy(1)); 705 | irqDisable(IRQ_HBLANK); 706 | } 707 | setupConsole(); 708 | consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); 709 | consoleClear(); 710 | iprintf ("Start failed. Error %i\n", err); 711 | if (err == 1) printf ("bootloader.nds not found!"); 712 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 713 | consoleClear(); 714 | } else { 715 | if ((splashFound[true] || splashFound[false]) && rgb565BmpDisplayMode) { 716 | while (dmaBusy(0) || dmaBusy(1)); 717 | irqDisable(IRQ_HBLANK); 718 | } 719 | setupConsole(); 720 | consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); 721 | consoleClear(); 722 | iprintf("Error!\n"); 723 | iprintf("\n"); 724 | iprintf("Launcher's title.tmd was\n"); 725 | iprintf("not found!"); 726 | consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); 727 | consoleClear(); 728 | } 729 | 730 | while (1) 731 | swiWaitForVBlank(); 732 | } 733 | 734 | --------------------------------------------------------------------------------