├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── link.ld ├── resources ├── BrahmaAppInfo ├── BrahmaIcon.png ├── CakesROP │ ├── drunkenlogo.grit │ └── drunkenlogo.png └── LauncherTemplate.dat └── source ├── common ├── common.h ├── hid.c ├── hid.h ├── i2c.c ├── i2c.h ├── memcpy.s ├── timer.c ├── timer.h ├── ui.c ├── ui.h └── unittype.h ├── crypto ├── aes.c ├── aes.h ├── keydb.c ├── keydb.h ├── sha.c └── sha.h ├── fatfs ├── 00history.txt ├── 00readme.txt ├── diskio.c ├── diskio.h ├── fatmbr.c ├── fatmbr.h ├── ff.c ├── ff.h ├── ffconf.h ├── integer.h ├── option │ ├── ccsbcs.c │ ├── syscall.c │ └── unicode.c ├── qff.c └── qff.h ├── font ├── font.h ├── font_6x10.h ├── font_acorn_8x8.h ├── font_gb_7x6.h └── font_orig.h ├── installer.c ├── installer.h ├── main.c ├── nand ├── delay.s ├── nand.c ├── nand.h ├── sdmmc.c └── sdmmc.h ├── safety ├── safewrite.c ├── safewrite.h ├── validator.c └── validator.h └── start.s /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | # Build directories 35 | /build 36 | /output 37 | /release 38 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "BrahmaLoader"] 2 | path = BrahmaLoader 3 | url = https://github.com/d0k3/BrahmaLoader.git 4 | ignore = dirty 5 | [submodule "CakesROP"] 6 | path = CakesROP 7 | url = https://github.com/mid-kid/CakesROP.git 8 | ignore = dirty 9 | [submodule "CakeHax"] 10 | path = CakeHax 11 | url = https://github.com/dukesrg/CakeHax.git 12 | [submodule "2xrsa"] 13 | path = 2xrsa 14 | url = https://github.com/b1l1s/2xrsa.git 15 | ignore = dirty 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | include $(DEVKITARM)/ds_rules 10 | 11 | #--------------------------------------------------------------------------------- 12 | # TARGET is the name of the output 13 | # BUILD is the directory where object files & intermediate files will be placed 14 | # SOURCES is a list of directories containing source code 15 | # DATA is a list of directories containing data files 16 | # INCLUDES is a list of directories containing header files 17 | # SPECS is the directory containing the important build and link files 18 | #--------------------------------------------------------------------------------- 19 | export TARGET := SafeB9SInstaller 20 | BUILD := build 21 | SOURCES := source source/common source/fs source/crypto source/fatfs source/nand source/safety 22 | DATA := data 23 | INCLUDES := source source/common source/font source/fs source/crypto source/fatfs source/nand source/safety 24 | 25 | #--------------------------------------------------------------------------------- 26 | # options for code generation 27 | #--------------------------------------------------------------------------------- 28 | ARCH := -mthumb -mthumb-interwork 29 | 30 | CFLAGS := -g -Wall -Wextra -Wpedantic -Wcast-align -Wno-main -O2\ 31 | -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -std=gnu11\ 32 | -fno-builtin-memcpy $(ARCH) -fdata-sections -ffunction-sections 33 | 34 | CFLAGS += $(INCLUDE) -DARM9 35 | 36 | CFLAGS += -DBUILD_NAME="\"$(TARGET) `date +'%Y/%m/%d'`\"" 37 | 38 | ifeq ($(FONT),ORIG) 39 | CFLAGS += -DFONT_ORIGINAL 40 | else ifeq ($(FONT),6X10) 41 | CFLAGS += -DFONT_6X10 42 | else ifeq ($(FONT),ACORN) 43 | CFLAGS += -DFONT_ACORN 44 | else ifeq ($(FONT),GB) 45 | CFLAGS += -DFONT_GB 46 | else 47 | CFLAGS += -DFONT_6X10 48 | endif 49 | 50 | ifeq ($(OPEN),1) 51 | CFLAGS += -DOPEN_INSTALLER 52 | endif 53 | 54 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 55 | 56 | ASFLAGS := -g -mcpu=arm946e-s $(ARCH) 57 | LDFLAGS = -T../link.ld -nostartfiles -g $(ARCH) -Wl,-Map,$(TARGET).map 58 | 59 | LIBS := 60 | 61 | #--------------------------------------------------------------------------------- 62 | # list of directories containing libraries, this must be the top level containing 63 | # include and lib 64 | #--------------------------------------------------------------------------------- 65 | LIBDIRS := 66 | 67 | #--------------------------------------------------------------------------------- 68 | # no real need to edit anything past this point unless you need to add additional 69 | # rules for different file extensions 70 | #--------------------------------------------------------------------------------- 71 | ifneq ($(BUILD),$(notdir $(CURDIR))) 72 | #--------------------------------------------------------------------------------- 73 | 74 | export OUTPUT_D := $(CURDIR)/output 75 | export OUTPUT := $(OUTPUT_D)/$(TARGET) 76 | export RELEASE := $(CURDIR)/release 77 | 78 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 79 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 80 | 81 | export DEPSDIR := $(CURDIR)/$(BUILD) 82 | 83 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 84 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 85 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 86 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 87 | 88 | #--------------------------------------------------------------------------------- 89 | # use CXX for linking C++ projects, CC for standard C 90 | #--------------------------------------------------------------------------------- 91 | ifeq ($(strip $(CPPFILES)),) 92 | #--------------------------------------------------------------------------------- 93 | export LD := $(CC) 94 | #--------------------------------------------------------------------------------- 95 | else 96 | #--------------------------------------------------------------------------------- 97 | export LD := $(CXX) 98 | #--------------------------------------------------------------------------------- 99 | endif 100 | #--------------------------------------------------------------------------------- 101 | 102 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 103 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 104 | 105 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 106 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 107 | -I$(CURDIR)/$(BUILD) 108 | 109 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 110 | 111 | .PHONY: common clean all gateway firm 2xrsa binary cakehax cakerop brahma release 112 | 113 | #--------------------------------------------------------------------------------- 114 | all: firm 115 | 116 | common: 117 | @[ -d $(OUTPUT_D) ] || mkdir -p $(OUTPUT_D) 118 | @[ -d $(BUILD) ] || mkdir -p $(BUILD) 119 | 120 | submodules: 121 | @-git submodule update --init --recursive 122 | 123 | binary: common 124 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 125 | 126 | firm: binary 127 | @firmtool build $(OUTPUT).firm -n 0x23F00000 -e 0 -D $(OUTPUT).bin -A 0x23F00000 -C NDMA -i 128 | 129 | gateway: binary 130 | @cp resources/LauncherTemplate.dat $(OUTPUT_D)/Launcher.dat 131 | @dd if=$(OUTPUT).bin of=$(OUTPUT_D)/Launcher.dat bs=1497296 seek=1 conv=notrunc 132 | 133 | 2xrsa: binary 134 | @make --no-print-directory -C 2xrsa 135 | @mv $(OUTPUT).bin $(OUTPUT_D)/arm9.bin 136 | @mv $(CURDIR)/2xrsa/bin/arm11.bin $(OUTPUT_D)/arm11.bin 137 | 138 | cakehax: submodules binary 139 | @make dir_out=$(OUTPUT_D) name=$(TARGET).dat -C CakeHax bigpayload 140 | @dd if=$(OUTPUT).bin of=$(OUTPUT).dat bs=512 seek=160 141 | 142 | cakerop: cakehax 143 | @make DATNAME=$(TARGET).dat DISPNAME=$(TARGET) GRAPHICS=../resources/CakesROP -C CakesROP 144 | @mv CakesROP/CakesROP.nds $(OUTPUT_D)/$(TARGET).nds 145 | 146 | brahma: submodules binary 147 | @[ -d BrahmaLoader/data ] || mkdir -p BrahmaLoader/data 148 | @cp $(OUTPUT).bin BrahmaLoader/data/payload.bin 149 | @cp resources/BrahmaAppInfo BrahmaLoader/resources/AppInfo 150 | @cp resources/BrahmaIcon.png BrahmaLoader/resources/icon.png 151 | @make --no-print-directory -C BrahmaLoader APP_TITLE=$(TARGET) 152 | @mv BrahmaLoader/output/*.3dsx $(OUTPUT_D) 153 | @mv BrahmaLoader/output/*.smdh $(OUTPUT_D) 154 | 155 | release: 156 | @rm -fr $(BUILD) $(OUTPUT_D) $(RELEASE) 157 | @make --no-print-directory binary 158 | @-make --no-print-directory gateway 159 | @-make --no-print-directory firm 160 | @-make --no-print-directory 2xrsa 161 | @-make --no-print-directory cakerop 162 | @-make --no-print-directory brahma 163 | @[ -d $(RELEASE) ] || mkdir -p $(RELEASE) 164 | @[ -d $(RELEASE)/$(TARGET) ] || mkdir -p $(RELEASE)/$(TARGET) 165 | @cp $(OUTPUT).bin $(RELEASE) 166 | @-cp $(OUTPUT).firm $(RELEASE) 167 | @-cp $(OUTPUT_D)/arm9.bin $(RELEASE) 168 | @-cp $(OUTPUT_D)/arm11.bin $(RELEASE) 169 | @-cp $(OUTPUT).dat $(RELEASE) 170 | @-cp $(OUTPUT).nds $(RELEASE) 171 | @-cp $(OUTPUT).3dsx $(RELEASE)/$(TARGET) 172 | @-cp $(OUTPUT).smdh $(RELEASE)/$(TARGET) 173 | @-cp $(OUTPUT_D)/Launcher.dat $(RELEASE) 174 | @cp $(CURDIR)/README.md $(RELEASE) 175 | @-7z a $(RELEASE)/$(TARGET)-`date +'%Y%m%d-%H%M%S'`.zip $(RELEASE)/* 176 | 177 | #--------------------------------------------------------------------------------- 178 | clean: 179 | @echo clean CakeHax... 180 | @-make clean --no-print-directory -C CakeHax 181 | @echo clean CakesROP... 182 | @-make clean --no-print-directory -C CakesROP 183 | @echo clean BrahmaLoader... 184 | @-make clean --no-print-directory -C BrahmaLoader 185 | @echo clean 2xrsa... 186 | @-make clean --no-print-directory -C 2xrsa 187 | @echo clean SafeB9SInstaller... 188 | @rm -fr $(BUILD) $(OUTPUT_D) $(RELEASE) 189 | 190 | 191 | #--------------------------------------------------------------------------------- 192 | else 193 | 194 | DEPENDS := $(OFILES:.o=.d) 195 | 196 | #--------------------------------------------------------------------------------- 197 | # main targets 198 | #--------------------------------------------------------------------------------- 199 | $(OUTPUT).bin : $(OUTPUT).elf 200 | $(OUTPUT).elf : $(OFILES) 201 | 202 | 203 | #--------------------------------------------------------------------------------- 204 | %.bin: %.elf 205 | @$(OBJCOPY) --set-section-flags .bss=alloc,load,contents -O binary $< $@ 206 | @echo built ... $(notdir $@) 207 | 208 | 209 | -include $(DEPENDS) 210 | 211 | 212 | #--------------------------------------------------------------------------------------- 213 | endif 214 | #--------------------------------------------------------------------------------------- 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SafeB9SInstaller 2 | Safe, simple, user-friendly installer for sighaxed FIRMs 3 | 4 | For usage instructions, refer to [Plailect's guide](https://3ds.guide/). 5 | 6 | ## Credits 7 | * **Normmatt**, for sdmmc.c / sdmmc.h 8 | * **Cha(N)**, **Kane49**, and all other FatFS contributors for FatFS 9 | * **Myria** for the sighax bruteforcer and for finding the sighax (retail&dev) signature 10 | * **SciresM** for dumping boot9, creating boot9strap.firm and for being the first fearless person to test this 11 | * **hedgeberg** for her tireless efforts in dumping the bootrom 12 | * **TuxSH** for FIRM research and useful hints 13 | * **Plailect** for providing the guide and making this accessible to the common user 14 | * **stuckpixel** for his tireless behind-the-scenes work 15 | * **Gelex** for being of great help on countless occasions 16 | * The fine folks on **freenode #Cakey** 17 | * All **[3dbrew.org](https://www.3dbrew.org/wiki/Main_Page) editors** 18 | * Everyone I possibly forgot, if you think you deserve to be mentioned, just contact me! 19 | -------------------------------------------------------------------------------- /link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | SECTIONS 6 | { 7 | . = 0x23F00000; 8 | 9 | .text.start : ALIGN(4) { *(.text.start) } 10 | .text : ALIGN(4) { *(.text*) } 11 | .rodata : ALIGN(4) { *(.rodata*) } 12 | .data : ALIGN(4) { *(.data*) } 13 | .bss : ALIGN(4) { __bss_start = .; *(.bss* COMMON); __bss_end = .;} 14 | 15 | . = ALIGN(4); 16 | 17 | __end__ = ABSOLUTE(.); 18 | } 19 | -------------------------------------------------------------------------------- /resources/BrahmaAppInfo: -------------------------------------------------------------------------------- 1 | APP_TITLE = SafeSigHaxInstaller 2 | APP_DESCRIPTION = Safe, simple, user-friendly installer for sighaxed FIRMs 3 | APP_AUTHOR = d0k3 4 | 5 | PAYLOAD_MEM = 1 6 | VOODOO = 0x3F 7 | -------------------------------------------------------------------------------- /resources/BrahmaIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/d0k3/SafeB9SInstaller/107675e006c5c90226b3a68743857fb5f4a05fff/resources/BrahmaIcon.png -------------------------------------------------------------------------------- /resources/CakesROP/drunkenlogo.grit: -------------------------------------------------------------------------------- 1 | -W3 2 | # disable alpha and set opaque bit for all pixels 3 | -gT! 4 | 5 | # use lz77 compression 6 | -gzl 7 | 8 | # 16 bit bitmap 9 | -gB16 10 | 11 | -gb 12 | -------------------------------------------------------------------------------- /resources/CakesROP/drunkenlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/d0k3/SafeB9SInstaller/107675e006c5c90226b3a68743857fb5f4a05fff/resources/CakesROP/drunkenlogo.png -------------------------------------------------------------------------------- /resources/LauncherTemplate.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/d0k3/SafeB9SInstaller/107675e006c5c90226b3a68743857fb5f4a05fff/resources/LauncherTemplate.dat -------------------------------------------------------------------------------- /source/common/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define u8 uint8_t 12 | #define u16 uint16_t 13 | #define u32 uint32_t 14 | #define u64 uint64_t 15 | 16 | #define vu8 volatile u8 17 | #define vu16 volatile u16 18 | #define vu32 volatile u32 19 | #define vu64 volatile u64 20 | 21 | #define max(a,b) \ 22 | (((a) > (b)) ? (a) : (b)) 23 | #define min(a,b) \ 24 | (((a) < (b)) ? (a) : (b)) 25 | #define getbe16(d) \ 26 | (((d)[0]<<8) | (d)[1]) 27 | #define getbe32(d) \ 28 | ((((u32) getbe16(d))<<16) | ((u32) getbe16(d+2))) 29 | #define getbe64(d) \ 30 | ((((u64) getbe32(d))<<32) | ((u64) getbe32(d+4))) 31 | #define getle16(d) \ 32 | (((d)[1]<<8) | (d)[0]) 33 | #define getle32(d) \ 34 | ((((u32) getle16(d+2))<<16) | ((u32) getle16(d))) 35 | #define getle64(d) \ 36 | ((((u64) getle32(d+4))<<32) | ((u64) getle32(d))) 37 | #define align(v,a) \ 38 | (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) 39 | 40 | // SafeB9SInstaller version 41 | #define VERSION "0.0.7" 42 | 43 | // name of the FIRM to install (also name of the input path) 44 | #ifndef OPEN_INSTALLER 45 | #define NAME_FIRM "boot9strap" 46 | #else 47 | #define NAME_FIRM "sighax" 48 | #endif 49 | 50 | // input / output paths 51 | #define INPUT_PATH "0:/" NAME_FIRM 52 | 53 | // cosmetic stuff (for installer status) 54 | #ifndef OPEN_INSTALLER 55 | #define APP_TITLE "SafeB9SInstaller" " v" VERSION 56 | #define APP_URL "https://github.com/d0k3/SafeB9SInstaller" 57 | #define APP_USAGE "Usage instructions: https://%s.hacks.guide/", IS_DEVKIT ? "panda" : "3ds" 58 | #else 59 | #define APP_TITLE "OpenFirmInstaller" " v" VERSION 60 | #define APP_URL "https://github.com/d0k3/SafeB9SInstaller" 61 | #define APP_USAGE "Based on SafeB9SInstaller by d0k3" 62 | #endif 63 | 64 | // buffer area defines (big buffer for firm) 65 | #define WORK_BUFFER ((u8*) 0x21000000) 66 | #define WORK_BUFFER_SIZE (0x400000) 67 | #define FIRM_BUFFER ((u8*) 0x21400000) 68 | #define FIRM_BUFFER_SIZE (0x400000) 69 | #define NAND_BUFFER ((u8*) 0x21800000) 70 | #define NAND_BUFFER_SIZE (0x100000) 71 | 72 | // testfing flags, only useful to devs 73 | // #define NO_WRITE // disables all NAND writes, just for testing 74 | // #define FAIL_TEST // to test the emergency screen, only works with NO_TRANSFER defined 75 | 76 | inline u32 strchrcount(const char* str, char symbol) { 77 | u32 count = 0; 78 | for (u32 i = 0; str[i] != '\0'; i++) { 79 | if (str[i] == symbol) 80 | count++; 81 | } 82 | return count; 83 | } 84 | -------------------------------------------------------------------------------- /source/common/hid.c: -------------------------------------------------------------------------------- 1 | #include "hid.h" 2 | #include "i2c.h" 3 | #include "timer.h" 4 | 5 | u32 InputWait() { 6 | static u64 delay = 0; 7 | u32 pad_state_old = HID_STATE; 8 | u32 cart_state_old = CART_STATE; 9 | u32 sd_state_old = SD_STATE; 10 | delay = (delay) ? 72 : 128; 11 | timer_start(); 12 | while (true) { 13 | u32 pad_state = HID_STATE; 14 | if (!(pad_state & BUTTON_ANY)) { // no buttons pressed 15 | u32 cart_state = CART_STATE; 16 | if (cart_state != cart_state_old) 17 | return cart_state ? CART_INSERT : CART_EJECT; 18 | u32 sd_state = SD_STATE; 19 | if (sd_state != sd_state_old) 20 | return sd_state ? SD_INSERT : SD_EJECT; 21 | u32 special_key = i2cReadRegister(I2C_DEV_MCU, 0x10); 22 | if (special_key == 0x01) 23 | return pad_state | BUTTON_POWER; 24 | else if (special_key == 0x04) 25 | return pad_state | BUTTON_HOME; 26 | pad_state_old = pad_state; 27 | delay = 0; 28 | continue; 29 | } 30 | if ((pad_state == pad_state_old) && 31 | (!(pad_state & BUTTON_ARROW) || 32 | (delay && (timer_msec() < delay)))) 33 | continue; 34 | // make sure the key is pressed 35 | u32 t_pressed = 0; 36 | for(; (t_pressed < 0x13000) && (pad_state == HID_STATE); t_pressed++); 37 | if (t_pressed >= 0x13000) 38 | return pad_state; 39 | } 40 | } 41 | 42 | bool CheckButton(u32 button) { 43 | u32 t_pressed = 0; 44 | for(; (t_pressed < 0x13000) && ((HID_STATE & button) == button); t_pressed++); 45 | return (t_pressed >= 0x13000); 46 | } 47 | -------------------------------------------------------------------------------- /source/common/hid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | // see: http://3dbrew.org/wiki/CONFIG9_Registers 6 | // see: http://3dbrew.org/wiki/EMMC_Registers 7 | #define HID_STATE (~(*(volatile u32*)0x10146000) & BUTTON_ANY) 8 | #define CART_STATE (~(*(volatile u8*)0x10000010) & 0x1) 9 | #define SD_STATE ((*(volatile u16*)0x1000601C) & (0x1<<5)) 10 | 11 | 12 | #define BUTTON_A (1 << 0) 13 | #define BUTTON_B (1 << 1) 14 | #define BUTTON_SELECT (1 << 2) 15 | #define BUTTON_START (1 << 3) 16 | #define BUTTON_RIGHT (1 << 4) 17 | #define BUTTON_LEFT (1 << 5) 18 | #define BUTTON_UP (1 << 6) 19 | #define BUTTON_DOWN (1 << 7) 20 | #define BUTTON_R1 (1 << 8) 21 | #define BUTTON_L1 (1 << 9) 22 | #define BUTTON_X (1 << 10) 23 | #define BUTTON_Y (1 << 11) 24 | #define BUTTON_ANY 0x00000FFF 25 | #define BUTTON_ARROW (BUTTON_RIGHT|BUTTON_LEFT|BUTTON_UP|BUTTON_DOWN) 26 | 27 | // special buttons / cart / sd 28 | #define BUTTON_POWER (1 << 12) 29 | #define BUTTON_HOME (1 << 13) 30 | #define CART_INSERT (1 << 14) 31 | #define CART_EJECT (1 << 15) 32 | #define SD_INSERT (1 << 16) 33 | #define SD_EJECT (1 << 17) 34 | 35 | u32 InputWait(); 36 | bool CheckButton(u32 button); 37 | -------------------------------------------------------------------------------- /source/common/i2c.c: -------------------------------------------------------------------------------- 1 | #include "i2c.h" 2 | 3 | //----------------------------------------------------------------------------- 4 | 5 | static const struct { u8 bus_id, reg_addr; } dev_data[] = { 6 | {0, 0x4A}, {0, 0x7A}, {0, 0x78}, 7 | {1, 0x4A}, {1, 0x78}, {1, 0x2C}, 8 | {1, 0x2E}, {1, 0x40}, {1, 0x44}, 9 | {2, 0xD6}, {2, 0xD0}, {2, 0xD2}, 10 | {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, 11 | }; 12 | 13 | inline u8 i2cGetDeviceBusId(u8 device_id) { 14 | return dev_data[device_id].bus_id; 15 | } 16 | 17 | inline u8 i2cGetDeviceRegAddr(u8 device_id) { 18 | return dev_data[device_id].reg_addr; 19 | } 20 | 21 | //----------------------------------------------------------------------------- 22 | 23 | static vu8* reg_data_addrs[] = { 24 | (vu8*)(I2C1_REG_OFF + I2C_REG_DATA), 25 | (vu8*)(I2C2_REG_OFF + I2C_REG_DATA), 26 | (vu8*)(I2C3_REG_OFF + I2C_REG_DATA), 27 | }; 28 | 29 | inline vu8* i2cGetDataReg(u8 bus_id) { 30 | return reg_data_addrs[bus_id]; 31 | } 32 | 33 | //----------------------------------------------------------------------------- 34 | 35 | static vu8* reg_cnt_addrs[] = { 36 | (vu8*)(I2C1_REG_OFF + I2C_REG_CNT), 37 | (vu8*)(I2C2_REG_OFF + I2C_REG_CNT), 38 | (vu8*)(I2C3_REG_OFF + I2C_REG_CNT), 39 | }; 40 | 41 | inline vu8* i2cGetCntReg(u8 bus_id) { 42 | return reg_cnt_addrs[bus_id]; 43 | } 44 | 45 | //----------------------------------------------------------------------------- 46 | 47 | inline void i2cWaitBusy(u8 bus_id) { 48 | while (*i2cGetCntReg(bus_id) & 0x80); 49 | } 50 | 51 | inline bool i2cGetResult(u8 bus_id) { 52 | i2cWaitBusy(bus_id); 53 | return (*i2cGetCntReg(bus_id) >> 4) & 1; 54 | } 55 | 56 | void i2cStop(u8 bus_id, u8 arg0) { 57 | *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; 58 | i2cWaitBusy(bus_id); 59 | *i2cGetCntReg(bus_id) = 0xC5; 60 | } 61 | 62 | //----------------------------------------------------------------------------- 63 | 64 | bool i2cSelectDevice(u8 bus_id, u8 dev_reg) { 65 | i2cWaitBusy(bus_id); 66 | *i2cGetDataReg(bus_id) = dev_reg; 67 | *i2cGetCntReg(bus_id) = 0xC2; 68 | return i2cGetResult(bus_id); 69 | } 70 | 71 | bool i2cSelectRegister(u8 bus_id, u8 reg) { 72 | i2cWaitBusy(bus_id); 73 | *i2cGetDataReg(bus_id) = reg; 74 | *i2cGetCntReg(bus_id) = 0xC0; 75 | return i2cGetResult(bus_id); 76 | } 77 | 78 | //----------------------------------------------------------------------------- 79 | 80 | u8 i2cReadRegister(u8 dev_id, u8 reg) { 81 | u8 bus_id = i2cGetDeviceBusId(dev_id); 82 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 83 | 84 | for (size_t i = 0; i < 8; i++) { 85 | if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { 86 | if (i2cSelectDevice(bus_id, dev_addr | 1)) { 87 | i2cWaitBusy(bus_id); 88 | i2cStop(bus_id, 1); 89 | i2cWaitBusy(bus_id); 90 | return *i2cGetDataReg(bus_id); 91 | } 92 | } 93 | *i2cGetCntReg(bus_id) = 0xC5; 94 | i2cWaitBusy(bus_id); 95 | } 96 | return 0xff; 97 | } 98 | 99 | bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) { 100 | u8 bus_id = i2cGetDeviceBusId(dev_id); 101 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 102 | 103 | size_t j = 0; 104 | while (!i2cSelectDevice(bus_id, dev_addr) 105 | || !i2cSelectRegister(bus_id, reg) 106 | || !i2cSelectDevice(bus_id, dev_addr | 1)) 107 | { 108 | i2cWaitBusy(bus_id); 109 | *i2cGetCntReg(bus_id) = 0xC5; 110 | i2cWaitBusy(bus_id); 111 | if (++j >= 8) 112 | return false; 113 | } 114 | 115 | if (buf_size != 1) { 116 | for (size_t i = 0; i < buf_size - 1; i++) { 117 | i2cWaitBusy(bus_id); 118 | *i2cGetCntReg(bus_id) = 0xF0; 119 | i2cWaitBusy(bus_id); 120 | buffer[i] = *i2cGetDataReg(bus_id); 121 | } 122 | } 123 | 124 | i2cWaitBusy(bus_id); 125 | *i2cGetCntReg(bus_id) = 0xE1; 126 | i2cWaitBusy(bus_id); 127 | buffer[buf_size - 1] = *i2cGetDataReg(bus_id); 128 | return true; 129 | } 130 | 131 | bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { 132 | u8 bus_id = i2cGetDeviceBusId(dev_id); 133 | u8 dev_addr = i2cGetDeviceRegAddr(dev_id); 134 | 135 | for (int i = 0; i < 8; i++) { 136 | if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { 137 | i2cWaitBusy(bus_id); 138 | *i2cGetDataReg(bus_id) = data; 139 | *i2cGetCntReg(bus_id) = 0xC1; 140 | i2cStop(bus_id, 0); 141 | if (i2cGetResult(bus_id)) 142 | return true; 143 | } 144 | *i2cGetCntReg(bus_id) = 0xC5; 145 | i2cWaitBusy(bus_id); 146 | } 147 | 148 | return false; 149 | } 150 | -------------------------------------------------------------------------------- /source/common/i2c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | #define I2C1_REG_OFF 0x10161000 6 | #define I2C2_REG_OFF 0x10144000 7 | #define I2C3_REG_OFF 0x10148000 8 | 9 | #define I2C_REG_DATA 0 10 | #define I2C_REG_CNT 1 11 | #define I2C_REG_CNTEX 2 12 | #define I2C_REG_SCL 4 13 | 14 | #define I2C_DEV_MCU 3 15 | #define I2C_DEV_GYRO 10 16 | #define I2C_DEV_IR 13 17 | 18 | u8 i2cGetDeviceBusId(u8 device_id); 19 | u8 i2cGetDeviceRegAddr(u8 device_id); 20 | 21 | vu8* i2cGetDataReg(u8 bus_id); 22 | vu8* i2cGetCntReg(u8 bus_id); 23 | 24 | void i2cWaitBusy(u8 bus_id); 25 | bool i2cGetResult(u8 bus_id); 26 | u8 i2cGetData(u8 bus_id); 27 | void i2cStop(u8 bus_id, u8 arg0); 28 | 29 | bool i2cSelectDevice(u8 bus_id, u8 dev_reg); 30 | bool i2cSelectRegister(u8 bus_id, u8 reg); 31 | 32 | u8 i2cReadRegister(u8 dev_id, u8 reg); 33 | bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); 34 | 35 | bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size); 36 | -------------------------------------------------------------------------------- /source/common/memcpy.s: -------------------------------------------------------------------------------- 1 | @ memcpy_arm946e-s - hand written reimplementation of memcpy to be sequential 2 | @ Written in 2019 by luigoalma 3 | @ To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. 4 | @ For a copy of CC0 Public Domain Dedication, see . 5 | .cpu arm946e-s 6 | .arch armv5te 7 | .arm 8 | .section .text.memcpy, "ax", %progbits 9 | .align 2 10 | .global memcpy 11 | .syntax unified 12 | .type memcpy, %function 13 | memcpy: 14 | @ r0 = dest 15 | @ r1 = src 16 | @ r2 = length 17 | @ check if length 0 and return if so 18 | cmp r2, #0 19 | bxeq lr 20 | push {r0,r4-r9,lr} 21 | @ pre-fetch data 22 | pld [r1] 23 | @ alignment check with word size 24 | @ if not aligned but both are in the same misalignment, fix it up 25 | @ otherwise jump to basic loop 26 | orr r12, r0, r1 27 | ands r12, r12, #3 28 | beq .L1 29 | and r4, r0, #3 30 | and r5, r1, #3 31 | cmp r4, r5 32 | bne .L6 33 | rsb r4, r4, #4 34 | .L0: 35 | ldrb r3, [r1], #1 36 | strb r3, [r0], #1 37 | subs r2, r2, #1 38 | popeq {r0,r4-r9,pc} 39 | subs r4, r4, #1 40 | bne .L0 41 | .L1: 42 | @ check if length higher than 32 43 | @ if so, do the 32 byte block copy loop, 44 | @ until there's nothing left or remainder to copy is less than 32 45 | movs r3, r2, LSR#5 46 | beq .L3 47 | .L2: 48 | ldm r1!, {r4-r9,r12,lr} 49 | stm r0!, {r4-r9,r12,lr} 50 | subs r3, r3, #1 51 | bne .L2 52 | ands r2, r2, #0x1F 53 | popeq {r0,r4-r9,pc} 54 | .L3: 55 | @ copy in word size the remaining data, 56 | @ and finish off with basic loop if can't copy all by word size. 57 | movs r3, r2, LSR#2 58 | beq .L6 59 | .L4: 60 | ldr r12, [r1], #4 61 | str r12, [r0], #4 62 | subs r3, r3, #1 63 | bne .L4 64 | ands r2, r2, #0x3 65 | .L5: @ the basic loop 66 | popeq {r0,r4-r9,pc} 67 | .L6: 68 | ldrb r3, [r1], #1 69 | strb r3, [r0], #1 70 | subs r2, r2, #1 71 | b .L5 72 | .size memcpy, .-memcpy 73 | -------------------------------------------------------------------------------- /source/common/timer.c: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | 3 | void timer_start( void ) { 4 | // reset / deactivate timers 5 | *TIMER_CNT0 = 0; 6 | *TIMER_CNT1 = *TIMER_CNT2 = *TIMER_CNT3 = TIMER_COUNT_UP; 7 | *TIMER_VAL0 = *TIMER_VAL1 = *TIMER_VAL2 = *TIMER_VAL3 = 0; 8 | 9 | // start timers 10 | *TIMER_CNT0 = TIMER_ACTIVE; 11 | *TIMER_CNT1 = *TIMER_CNT2 = *TIMER_CNT3 = TIMER_ACTIVE | TIMER_COUNT_UP; 12 | } 13 | 14 | void timer_stop( void ) { 15 | *TIMER_CNT0 &= ~TIMER_ACTIVE; 16 | *TIMER_CNT1 &= ~TIMER_ACTIVE; 17 | *TIMER_CNT2 &= ~TIMER_ACTIVE; 18 | *TIMER_CNT3 &= ~TIMER_ACTIVE; 19 | } 20 | 21 | u64 timer_ticks( void ) { 22 | u64 ticks = 0; 23 | ticks |= (u64) *TIMER_VAL0 << 0; 24 | ticks |= (u64) *TIMER_VAL1 << 16; 25 | ticks |= (u64) *TIMER_VAL2 << 32; 26 | ticks |= (u64) *TIMER_VAL3 << 48; 27 | return ticks; 28 | } 29 | 30 | u64 timer_msec( void ) { 31 | return (timer_ticks() * 1000) / TICKS_PER_SEC; 32 | } 33 | 34 | u64 timer_sec( void ) { 35 | return timer_ticks() / TICKS_PER_SEC; 36 | } 37 | -------------------------------------------------------------------------------- /source/common/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | // see: https://www.3dbrew.org/wiki/TIMER_Registers 6 | #define TIMER_VAL0 ((vu16*)0x10003000) 7 | #define TIMER_VAL1 ((vu16*)0x10003004) 8 | #define TIMER_VAL2 ((vu16*)0x10003008) 9 | #define TIMER_VAL3 ((vu16*)0x1000300C) 10 | #define TIMER_CNT0 ((vu16*)0x10003002) 11 | #define TIMER_CNT1 ((vu16*)0x10003006) 12 | #define TIMER_CNT2 ((vu16*)0x1000300A) 13 | #define TIMER_CNT3 ((vu16*)0x1000300E) 14 | 15 | #define TIMER_COUNT_UP 0x0004 16 | #define TIMER_ACTIVE 0x0080 17 | #define TICKS_PER_SEC 67027964ULL 18 | 19 | void timer_start( void ); 20 | void timer_stop( void ); 21 | u64 timer_ticks( void ); 22 | u64 timer_msec( void ); 23 | u64 timer_sec( void ); 24 | -------------------------------------------------------------------------------- /source/common/ui.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Normmatt 2 | // Licensed under GPLv2 or any later version 3 | // Refer to the license.txt file included. 4 | 5 | #pragma once 6 | 7 | #include "common.h" 8 | 9 | #define BYTES_PER_PIXEL 3 10 | #define SCREEN_HEIGHT 240 11 | #define SCREEN_WIDTH_TOP 400 12 | #define SCREEN_WIDTH_BOT 320 13 | #ifdef FONT_6X10 14 | #define FONT_WIDTH_EXT 6 15 | #define FONT_HEIGHT_EXT 10 16 | #elif defined FONT_GB // special font width 17 | #define FONT_WIDTH_EXT 7 18 | #define FONT_HEIGHT_EXT 6 19 | #else 20 | #define FONT_WIDTH_EXT 8 21 | #define FONT_HEIGHT_EXT 8 22 | #endif 23 | 24 | #define RGB(r,g,b) ((r)<<24|(b)<<16|(g)<<8|(r)) 25 | 26 | #define COLOR_BLACK RGB(0x00, 0x00, 0x00) 27 | #define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF) 28 | #define COLOR_GREY RGB(0x80, 0x80, 0x80) 29 | 30 | #define COLOR_RED RGB(0xFF, 0x00, 0x00) 31 | #define COLOR_GREEN RGB(0x00, 0xFF, 0x00) 32 | #define COLOR_BLUE RGB(0x00, 0x00, 0xFF) 33 | #define COLOR_YELLOW RGB(0xFF, 0xFF, 0x00) 34 | #define COLOR_CYAN RGB(0xFF, 0x00, 0xFF) 35 | #define COLOR_ORANGE RGB(0xFF, 0xA5, 0x00) 36 | 37 | #define COLOR_BRIGHTRED RGB(0xFF, 0x30, 0x30) 38 | #define COLOR_DARKRED RGB(0x80, 0x00, 0x00) 39 | #define COLOR_BRIGHTYELLOW RGB(0xFF, 0xFF, 0x30) 40 | #define COLOR_BRIGHTGREEN RGB(0x30, 0xFF, 0x30) 41 | #define COLOR_BRIGHTBLUE RGB(0x30, 0x30, 0xFF) 42 | 43 | #define COLOR_TINTEDBLUE RGB(0x60, 0x60, 0x80) 44 | #define COLOR_TINTEDYELLOW RGB(0xD0, 0xD0, 0x60) 45 | #define COLOR_TINTEDGREEN RGB(0x70, 0x80, 0x70) 46 | #define COLOR_LIGHTGREY RGB(0xB0, 0xB0, 0xB0) 47 | #define COLOR_DARKGREY RGB(0x50, 0x50, 0x50) 48 | #define COLOR_DARKESTGREY RGB(0x20, 0x20, 0x20) 49 | 50 | #define COLOR_TRANSPARENT RGB(0xFF, 0x00, 0xEF) // otherwise known as 'super fuchsia' 51 | 52 | #define COLOR_STD_BG COLOR_BLACK 53 | #define COLOR_STD_FONT COLOR_WHITE 54 | 55 | #define TOP_SCREEN top_screen 56 | #define BOT_SCREEN bottom_screen 57 | 58 | extern u8 *top_screen, *bottom_screen; 59 | 60 | void ClearScreen(unsigned char *screen, int color); 61 | void ClearScreenF(bool clear_top, bool clear_bottom, int color); 62 | void DrawRectangle(u8* screen, int x, int y, int width, int height, int color); 63 | 64 | void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor); 65 | void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor); 66 | void DrawStringF(unsigned char *screen, int x, int y, int color, int bgcolor, const char *format, ...); 67 | 68 | u32 GetDrawStringHeight(const char* str); 69 | u32 GetDrawStringWidth(const char* str); 70 | 71 | void ResizeString(char* dest, const char* orig, int nsize, int tpos, bool align_right); 72 | void TruncateString(char* dest, const char* orig, int nsize, int tpos); 73 | void FormatNumber(char* str, u64 number); 74 | void FormatBytes(char* str, u64 bytes); 75 | 76 | void ShowString(const char *format, ...); 77 | bool ShowPrompt(bool ask, const char *format, ...); 78 | bool ShowUnlockSequence(u32 seqlvl, const char *format, ...); 79 | u32 ShowSelectPrompt(u32 n, const char** options, const char *format, ...); 80 | bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...); 81 | u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...); 82 | u64 ShowNumberPrompt(u64 start_val, const char *format, ...); 83 | bool ShowDataPrompt(u8* data, u32* size, const char *format, ...); 84 | bool ShowProgress(u64 current, u64 total, const char* opstr); 85 | -------------------------------------------------------------------------------- /source/common/unittype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | // see: https://3dbrew.org/wiki/CONFIG11_Registers 6 | #define IS_O3DS ((*(vu32*) 0x10140FFC) != 0x7) 7 | 8 | // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM 9 | // see: https://www.3dbrew.org/wiki/OTP_Registers#Plaintext_OTP 10 | #define IS_DEVKIT ((*(vu8*) (0x01FFB800+0x19)) != 0x0) 11 | 12 | // see: https://3dbrew.org/wiki/CONFIG11_Registers 13 | // (also returns true for sighaxed systems, maybe change the name later?) 14 | #define IS_A9LH ((*(vu32*) 0x101401C0) == 0) 15 | 16 | // https://www.3dbrew.org/wiki/CONFIG9_Registers 17 | // (actually checks for an unlocked OTP) 18 | #define IS_UNLOCKED (!((*(vu8*)0x10000000) & 0x2)) 19 | 20 | // A9LH + unlocked == SigHax 21 | #define IS_SIGHAX (IS_A9LH && IS_UNLOCKED) 22 | -------------------------------------------------------------------------------- /source/crypto/aes.c: -------------------------------------------------------------------------------- 1 | /* original version by megazig */ 2 | #include "aes.h" 3 | 4 | //FIXME some things make assumptions about alignemnts! 5 | 6 | void setup_aeskeyX(uint8_t keyslot, const void* keyx) 7 | { 8 | const uint32_t * _keyx = (const uint32_t*)keyx; 9 | *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; 10 | *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; 11 | if (keyslot > 3) { 12 | *REG_AESKEYXFIFO = _keyx[0]; 13 | *REG_AESKEYXFIFO = _keyx[1]; 14 | *REG_AESKEYXFIFO = _keyx[2]; 15 | *REG_AESKEYXFIFO = _keyx[3]; 16 | } else { 17 | uint32_t old_aescnt = *REG_AESCNT; 18 | volatile uint32_t* reg_aeskeyx = REG_AESKEY0123 + (((0x30u * keyslot) + 0x10u)/4u); 19 | *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); 20 | for (uint32_t i = 0; i < 4u; i++) 21 | reg_aeskeyx[i] = _keyx[i]; 22 | *REG_AESCNT = old_aescnt; 23 | } 24 | } 25 | 26 | void setup_aeskeyY(uint8_t keyslot, const void* keyy) 27 | { 28 | const uint32_t * _keyy = (const uint32_t*)keyy; 29 | *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; 30 | *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; 31 | if (keyslot > 3) { 32 | *REG_AESKEYYFIFO = _keyy[0]; 33 | *REG_AESKEYYFIFO = _keyy[1]; 34 | *REG_AESKEYYFIFO = _keyy[2]; 35 | *REG_AESKEYYFIFO = _keyy[3]; 36 | } else { 37 | uint32_t old_aescnt = *REG_AESCNT; 38 | volatile uint32_t* reg_aeskeyy = REG_AESKEY0123 + (((0x30u * keyslot) + 0x20u)/4u); 39 | *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); 40 | for (uint32_t i = 0; i < 4u; i++) 41 | reg_aeskeyy[i] = _keyy[i]; 42 | *REG_AESCNT = old_aescnt; 43 | } 44 | } 45 | 46 | void setup_aeskey(uint8_t keyslot, const void* key) 47 | { 48 | const uint32_t * _key = (const uint32_t*)key; 49 | *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; 50 | *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; 51 | if (keyslot > 3) { 52 | *REG_AESKEYFIFO = _key[0]; 53 | *REG_AESKEYFIFO = _key[1]; 54 | *REG_AESKEYFIFO = _key[2]; 55 | *REG_AESKEYFIFO = _key[3]; 56 | } else { 57 | uint32_t old_aescnt = *REG_AESCNT; 58 | volatile uint32_t* reg_aeskey = REG_AESKEY0123 + ((0x30u * keyslot)/4u); 59 | *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); 60 | for (uint32_t i = 0; i < 4u; i++) 61 | reg_aeskey[i] = _key[i]; 62 | *REG_AESCNT = old_aescnt; 63 | } 64 | } 65 | 66 | void use_aeskey(uint32_t keyno) 67 | { 68 | if (keyno > 0x3F) 69 | return; 70 | *REG_AESKEYSEL = keyno; 71 | *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ 72 | } 73 | 74 | void set_ctr(void* iv) 75 | { 76 | uint32_t * _iv = (uint32_t*)iv; 77 | *REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER; 78 | *(REG_AESCTR + 0) = _iv[3]; 79 | *(REG_AESCTR + 1) = _iv[2]; 80 | *(REG_AESCTR + 2) = _iv[1]; 81 | *(REG_AESCTR + 3) = _iv[0]; 82 | } 83 | 84 | void add_ctr(void* ctr, uint32_t carry) 85 | { 86 | uint32_t counter[4]; 87 | uint8_t *outctr = (uint8_t *) ctr; 88 | uint32_t sum; 89 | int32_t i; 90 | 91 | for(i = 0; i < 4; i++) { 92 | //FIXME this assumes alignment... 93 | counter[i] = ((uint32_t)outctr[i*4+0]<<24) | ((uint32_t)outctr[i*4+1]<<16) | ((uint32_t)outctr[i*4+2]<<8) | ((uint32_t)outctr[i*4+3]<<0); 94 | } 95 | 96 | for(i=3; i>=0; i--) 97 | { 98 | sum = counter[i] + carry; 99 | if (sum < counter[i]) { 100 | carry = 1; 101 | } 102 | else { 103 | carry = 0; 104 | } 105 | counter[i] = sum; 106 | } 107 | 108 | for(i=0; i<4; i++) 109 | { 110 | outctr[i*4+0] = counter[i]>>24; 111 | outctr[i*4+1] = counter[i]>>16; 112 | outctr[i*4+2] = counter[i]>>8; 113 | outctr[i*4+3] = counter[i]>>0; 114 | } 115 | } 116 | 117 | void subtract_ctr(void* ctr, uint32_t carry) 118 | { 119 | //ctr is in big endian format, 16 bytes 120 | uint32_t counter[4]; 121 | uint8_t *outctr = (uint8_t *) ctr; 122 | 123 | //Convert each 4 byte part of ctr to uint32_t equivalents 124 | for(size_t i = 0; i < 4; i++) { 125 | //FIXME this assumes alignment... 126 | counter[i] = ((uint32_t)outctr[i*4+0]<<24) | ((uint32_t)outctr[i*4+1]<<16) | ((uint32_t)outctr[i*4+2]<<8) | ((uint32_t)outctr[i*4+3]<<0); 127 | } 128 | 129 | for(size_t i = 0; i < 4; ++i) 130 | { 131 | uint32_t sub; 132 | //using modular arithmetic to handle carry 133 | sub = counter[3-i] - carry; 134 | carry = counter[3-i] < carry; 135 | 136 | counter[3-i] = sub; 137 | } 138 | 139 | for(size_t i = 0; i < 4; i++) 140 | { 141 | outctr[i*4+0] = counter[i]>>24; 142 | outctr[i*4+1] = counter[i]>>16; 143 | outctr[i*4+2] = counter[i]>>8; 144 | outctr[i*4+3] = counter[i]>>0; 145 | } 146 | } 147 | 148 | void ecb_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode) 149 | { 150 | aes_decrypt(inbuf, outbuf, size, mode); 151 | } 152 | 153 | void cbc_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *ctr) 154 | { 155 | size_t blocks_left = size; 156 | size_t blocks; 157 | uint8_t *in = inbuf; 158 | uint8_t *out = outbuf; 159 | uint32_t i; 160 | 161 | while (blocks_left) 162 | { 163 | set_ctr(ctr); 164 | blocks = (blocks_left >= 0xFFFF) ? 0xFFFF : blocks_left; 165 | for (i=0; i= 0xFFFF) ? 0xFFFF : blocks_left; 186 | aes_decrypt(in, out, blocks, mode); 187 | for (i=0; i= AES_BLOCK_SIZE) ? 212 | AES_BLOCK_SIZE : off_fix + bytes_left; 213 | for (i=off_fix; i= AES_BLOCK_SIZE) 222 | { 223 | size_t blocks = bytes_left / AES_BLOCK_SIZE; 224 | ctr_decrypt(in, out, blocks, mode, ctr_local); 225 | in += AES_BLOCK_SIZE * blocks; 226 | out += AES_BLOCK_SIZE * blocks; 227 | bytes_left -= AES_BLOCK_SIZE * blocks; 228 | } 229 | 230 | if (bytes_left) // handle misaligned offset (at end) 231 | { 232 | for (i=0; i= 0xFFFF) ? 0xFFFF : blocks_left; 252 | aes_decrypt(in, out, blocks, mode); 253 | add_ctr(ctr, blocks); 254 | in += blocks * AES_BLOCK_SIZE; 255 | out += blocks * AES_BLOCK_SIZE; 256 | blocks_left -= blocks; 257 | } 258 | } 259 | 260 | void aes_decrypt(void* inbuf, void* outbuf, size_t size, uint32_t mode) 261 | { 262 | uint8_t *in = inbuf; 263 | uint8_t *out = outbuf; 264 | size_t block_count = size; 265 | size_t blocks; 266 | while (block_count != 0) 267 | { 268 | blocks = (block_count >= 0xFFFF) ? 0xFFFF : block_count; 269 | *REG_AESCNT = 0; 270 | *REG_AESBLKCNT = blocks << 16; 271 | *REG_AESCNT = mode | 272 | AES_CNT_START | 273 | AES_CNT_FLUSH_READ | 274 | AES_CNT_FLUSH_WRITE; 275 | aes_fifos((void*)in, (void*)out, blocks); 276 | in += blocks * AES_BLOCK_SIZE; 277 | out += blocks * AES_BLOCK_SIZE; 278 | block_count -= blocks; 279 | } 280 | } 281 | 282 | void aes_cmac(void* inbuf, void* outbuf, size_t size) 283 | { 284 | // only works for full blocks 285 | uint32_t zeroes[4] __attribute__((aligned(32))) = { 0 }; 286 | uint32_t xorpad[4] __attribute__((aligned(32))) = { 0 }; 287 | uint32_t mode = AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | 288 | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN; 289 | uint32_t* out = (uint32_t*) outbuf; 290 | uint32_t* in = (uint32_t*) inbuf; 291 | 292 | // create xorpad for last block 293 | set_ctr(zeroes); 294 | aes_decrypt(xorpad, xorpad, 1, mode); 295 | char* xorpadb = (void*) xorpad; 296 | char finalxor = (xorpadb[0] & 0x80) ? 0x87 : 0x00; 297 | for (uint32_t i = 0; i < 15; i++) { 298 | xorpadb[i] <<= 1; 299 | xorpadb[i] |= xorpadb[i+1] >> 7; 300 | } 301 | xorpadb[15] <<= 1; 302 | xorpadb[15] ^= finalxor; 303 | 304 | // process blocks 305 | for (uint32_t i = 0; i < 4; i++) 306 | out[i] = 0; 307 | while (size-- > 0) { 308 | for (uint32_t i = 0; i < 4; i++) 309 | out[i] ^= *(in++); 310 | if (!size) { // last block 311 | for (uint32_t i = 0; i < 4; i++) 312 | out[i] ^= xorpad[i]; 313 | } 314 | set_ctr(zeroes); 315 | aes_decrypt(out, out, 1, mode); 316 | } 317 | } 318 | 319 | void aes_fifos(void* inbuf, void* outbuf, size_t blocks) 320 | { 321 | if (!inbuf || !outbuf) return; 322 | 323 | uint8_t *in = inbuf; 324 | uint8_t *out = outbuf; 325 | 326 | size_t curblock = 0; 327 | while (curblock != blocks) 328 | { 329 | while (aescnt_checkwrite()); 330 | 331 | size_t blocks_to_read = blocks - curblock > 4 ? 4 : blocks - curblock; 332 | 333 | for (size_t wblocks = 0; wblocks < blocks_to_read; ++wblocks) 334 | for (uint8_t *ii = in + AES_BLOCK_SIZE * wblocks; ii != in + (AES_BLOCK_SIZE * (wblocks + 1)); ii += 4) 335 | { 336 | uint32_t data = ii[0]; 337 | data |= (uint32_t)(ii[1]) << 8; 338 | data |= (uint32_t)(ii[2]) << 16; 339 | data |= (uint32_t)(ii[3]) << 24; 340 | set_aeswrfifo(data); 341 | } 342 | 343 | if (out) 344 | { 345 | for (size_t rblocks = 0; rblocks < blocks_to_read; ++rblocks) 346 | { 347 | while (aescnt_checkread()) ; 348 | for (uint8_t *ii = out + AES_BLOCK_SIZE * rblocks; ii != out + (AES_BLOCK_SIZE * (rblocks + 1)); ii += 4) 349 | { 350 | uint32_t data = read_aesrdfifo(); 351 | ii[0] = data; 352 | ii[1] = data >> 8; 353 | ii[2] = data >> 16; 354 | ii[3] = data >> 24; 355 | } 356 | } 357 | } 358 | 359 | in += blocks_to_read * AES_BLOCK_SIZE; 360 | out += blocks_to_read * AES_BLOCK_SIZE; 361 | curblock += blocks_to_read; 362 | } 363 | } 364 | 365 | void set_aeswrfifo(uint32_t value) 366 | { 367 | *REG_AESWRFIFO = value; 368 | } 369 | 370 | uint32_t read_aesrdfifo(void) 371 | { 372 | return *REG_AESRDFIFO; 373 | } 374 | 375 | uint32_t aes_getwritecount() 376 | { 377 | return *REG_AESCNT & 0x1F; 378 | } 379 | 380 | uint32_t aes_getreadcount() 381 | { 382 | return (*REG_AESCNT >> 5) & 0x1F; 383 | } 384 | 385 | uint32_t aescnt_checkwrite() 386 | { 387 | size_t ret = aes_getwritecount(); 388 | return (ret > 0xF); 389 | } 390 | 391 | uint32_t aescnt_checkread() 392 | { 393 | size_t ret = aes_getreadcount(); 394 | return (ret <= 3); 395 | } 396 | 397 | -------------------------------------------------------------------------------- /source/crypto/aes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define AES_BLOCK_SIZE 0x10 11 | 12 | #define AES_CCM_DECRYPT_MODE (0u << 27) 13 | #define AES_CCM_ENCRYPT_MODE (1u << 27) 14 | #define AES_CTR_MODE (2u << 27) 15 | #define AES_CBC_DECRYPT_MODE (4u << 27) 16 | #define AES_CBC_ENCRYPT_MODE (5u << 27) 17 | #define AES_ECB_DECRYPT_MODE (6u << 27) 18 | #define AES_ECB_ENCRYPT_MODE (7u << 27) 19 | 20 | #define REG_AESCNT ((volatile uint32_t*)0x10009000) 21 | #define REG_AESBLKCNT ((volatile uint32_t*)0x10009004) 22 | #define REG_AESWRFIFO ((volatile uint32_t*)0x10009008) 23 | #define REG_AESRDFIFO ((volatile uint32_t*)0x1000900C) 24 | #define REG_AESKEYSEL ((volatile uint8_t *)0x10009010) 25 | #define REG_AESKEYCNT ((volatile uint8_t *)0x10009011) 26 | #define REG_AESCTR ((volatile uint32_t*)0x10009020) 27 | #define REG_AESKEYFIFO ((volatile uint32_t*)0x10009100) 28 | #define REG_AESKEYXFIFO ((volatile uint32_t*)0x10009104) 29 | #define REG_AESKEYYFIFO ((volatile uint32_t*)0x10009108) 30 | #define REG_AESMAC ((volatile uint32_t*)0x10009030) 31 | // see https://www.3dbrew.org/wiki/AES_Registers#AES_KEY0.2F1.2F2.2F3 32 | #define REG_AESKEY0123 ((volatile uint32_t*)0x10009040) 33 | 34 | #define AES_CNT_START 0x80000000u 35 | #define AES_CNT_INPUT_ORDER 0x02000000u 36 | #define AES_CNT_OUTPUT_ORDER 0x01000000u 37 | #define AES_CNT_INPUT_ENDIAN 0x00800000u 38 | #define AES_CNT_OUTPUT_ENDIAN 0x00400000u 39 | #define AES_CNT_FLUSH_READ 0x00000800u 40 | #define AES_CNT_FLUSH_WRITE 0x00000400u 41 | 42 | #define AES_CNT_CTRNAND_MODE (AES_CTR_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 43 | #define AES_CNT_TWLNAND_MODE AES_CTR_MODE 44 | #define AES_CNT_TITLEKEY_DECRYPT_MODE (AES_CBC_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 45 | #define AES_CNT_TITLEKEY_ENCRYPT_MODE (AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 46 | #define AES_CNT_ECB_DECRYPT_MODE (AES_ECB_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 47 | #define AES_CNT_ECB_ENCRYPT_MODE (AES_ECB_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) 48 | 49 | void setup_aeskeyX(uint8_t keyslot, const void* keyx); 50 | void setup_aeskeyY(uint8_t keyslot, const void* keyy); 51 | void setup_aeskey(uint8_t keyslot, const void* keyy); 52 | void use_aeskey(uint32_t keyno); 53 | void set_ctr(void* iv); 54 | void add_ctr(void* ctr, uint32_t carry); 55 | void subtract_ctr(void* ctr, uint32_t carry); 56 | void aes_decrypt(void* inbuf, void* outbuf, size_t size, uint32_t mode); 57 | void ctr_decrypt(void* inbuf, void* outbuf, size_t size, uint32_t mode, uint8_t *ctr); 58 | void ctr_decrypt_byte(void *inbuf, void *outbuf, size_t size, size_t off, uint32_t mode, uint8_t *ctr); 59 | void ecb_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode); 60 | void cbc_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *ctr); 61 | void cbc_encrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *ctr); 62 | void aes_cmac(void* inbuf, void* outbuf, size_t size); 63 | void aes_fifos(void* inbuf, void* outbuf, size_t blocks); 64 | void set_aeswrfifo(uint32_t value); 65 | uint32_t read_aesrdfifo(void); 66 | uint32_t aes_getwritecount(void); 67 | uint32_t aes_getreadcount(void); 68 | uint32_t aescnt_checkwrite(void); 69 | uint32_t aescnt_checkread(void); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | -------------------------------------------------------------------------------- /source/crypto/keydb.c: -------------------------------------------------------------------------------- 1 | #include "keydb.h" 2 | #include "aes.h" 3 | #include "sha.h" 4 | #include "ff.h" 5 | 6 | #define PATH_KEYDB INPUT_PATH "/" KEYDB_NAME 7 | 8 | typedef struct { 9 | u8 slot; // keyslot, 0x00...0x39 10 | char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV 11 | char id[10]; // key ID for special keys, all zero for standard keys 12 | } __attribute__((packed)) AesKeyDesc; 13 | 14 | typedef struct { 15 | AesKeyDesc desc; // slot, type, id 16 | u8 keyUnitType; // 0 for ALL units / 1 for devkit exclusive / 2 for retail exclusive 17 | u8 keySha256[32]; // SHA-256 of the key 18 | } __attribute__((packed)) AesKeyHashInfo; 19 | 20 | typedef struct { 21 | u8 slot; // keyslot, 0x00...0x39 22 | u8 keyUnitType; // 0 for ALL units / 1 for devkit exclusive / 2 for retail exclusive 23 | u8 sample[16]; // sample data, encoded with src = keyY = ctr = { 0 } 24 | } __attribute__((packed)) AesNcchSampleInfo; 25 | 26 | static u64 keyState = 0; 27 | static u64 keyXState = 0; 28 | static u64 keyYState = 0; 29 | 30 | u32 GetUnitKeysType(void) 31 | { 32 | static u32 keys_type = KEYS_UNKNOWN; 33 | 34 | if (keys_type == KEYS_UNKNOWN) { 35 | static const u8 slot0x2CSampleRetail[16] = { 36 | 0xBC, 0xC4, 0x16, 0x2C, 0x2A, 0x06, 0x91, 0xEE, 0x47, 0x18, 0x86, 0xB8, 0xEB, 0x2F, 0xB5, 0x48 }; 37 | static const u8 slot0x2CSampleDevkit[16] = { 38 | 0x29, 0xB5, 0x5D, 0x9F, 0x61, 0xAC, 0xD2, 0x28, 0x22, 0x23, 0xFB, 0x57, 0xDD, 0x50, 0x8A, 0xF5 }; 39 | static u8 zeroes[16] = { 0 }; 40 | u8 sample[16] = { 0 }; 41 | setup_aeskeyY(0x2C, zeroes); 42 | use_aeskey(0x2C); 43 | set_ctr(zeroes); 44 | aes_decrypt(sample, sample, 1, AES_CNT_CTRNAND_MODE); 45 | if (memcmp(sample, slot0x2CSampleRetail, 16) == 0) { 46 | keys_type = KEYS_RETAIL; 47 | } else if (memcmp(sample, slot0x2CSampleDevkit, 16) == 0) { 48 | keys_type = KEYS_DEVKIT; 49 | } 50 | } 51 | 52 | return keys_type; 53 | } 54 | 55 | void CryptAesKeyInfo(AesKeyInfo* info) { 56 | static u8 zeroes[16] = { 0 }; 57 | u8 ctr[16] = { 0 }; 58 | memcpy(ctr, (void*) info, 12); // CTR -> slot + type + id + zeroes 59 | setup_aeskeyY(0x2C, zeroes); 60 | use_aeskey(0x2C); 61 | set_ctr(ctr); 62 | aes_decrypt(info->key, info->key, 1, AES_CNT_CTRNAND_MODE); 63 | info->isEncrypted = !info->isEncrypted; 64 | } 65 | 66 | u32 CheckAesKeyInfo(u8* key, u32 keyslot, char type, char* id) 67 | { 68 | static const AesKeyHashInfo keyHashes[] = { 69 | { { 0x05, 'Y', "" }, KEYS_RETAIL, // Retail N3DS CTRNAND key SHA256 70 | { 0x98, 0x24, 0x27, 0x14, 0x22, 0xB0, 0x6B, 0xF2, 0x10, 0x96, 0x9C, 0x36, 0x42, 0x53, 0x7C, 0x86, 71 | 0x62, 0x22, 0x5C, 0xFD, 0x6F, 0xAE, 0x9B, 0x0A, 0x85, 0xA5, 0xCE, 0x21, 0xAA, 0xB6, 0xC8, 0x4D } 72 | }, 73 | { { 0x18, 'X', "" }, KEYS_RETAIL, // Retail NCCH Secure3 key SHA256 74 | { 0x76, 0xC7, 0x6B, 0x65, 0x5D, 0xB8, 0x52, 0x19, 0xC5, 0xD3, 0x5D, 0x51, 0x7F, 0xFA, 0xF7, 0xA4, 75 | 0x3E, 0xBA, 0xD6, 0x6E, 0x31, 0xFB, 0xDD, 0x57, 0x43, 0x92, 0x59, 0x37, 0xA8, 0x93, 0xCC, 0xFC } 76 | }, 77 | { { 0x1B, 'X', "" }, KEYS_RETAIL, // Retail NCCH Secure4 key SHA256 78 | { 0x9A, 0x20, 0x1E, 0x7C, 0x37, 0x37, 0xF3, 0x72, 0x2E, 0x5B, 0x57, 0x8D, 0x11, 0x83, 0x7F, 0x19, 79 | 0x7C, 0xA6, 0x5B, 0xF5, 0x26, 0x25, 0xB2, 0x69, 0x06, 0x93, 0xE4, 0x16, 0x53, 0x52, 0xC6, 0xBB } 80 | }, 81 | { { 0x25, 'X', "" }, KEYS_RETAIL, // Retail NCCH 7x key SHA256 82 | { 0x7E, 0x87, 0x8D, 0xDE, 0x92, 0x93, 0x8E, 0x4C, 0x71, 0x7D, 0xD5, 0x3D, 0x1E, 0xA3, 0x5A, 0x75, 83 | 0x63, 0x3F, 0x51, 0x30, 0xD8, 0xCF, 0xD7, 0xC7, 0x6C, 0x8F, 0x4A, 0x8F, 0xB8, 0x70, 0x50, 0xCD } 84 | }/*, 85 | { { 0x18, 'X', "" }, KEYS_DEVKIT, // DevKit NCCH Secure3 key SHA256 86 | { 0x08, 0xE1, 0x09, 0x62, 0xF6, 0x5A, 0x09, 0xAA, 0x12, 0x2C, 0x7C, 0xBE, 0xDE, 0xA1, 0x9C, 0x4B, 87 | 0x5C, 0x9A, 0x8A, 0xC3, 0xD9, 0x8E, 0xA1, 0x62, 0x04, 0x11, 0xD7, 0xE8, 0x55, 0x70, 0xA6, 0xC2 } 88 | }, 89 | { { 0x1B, 'X', "" }, KEYS_DEVKIT, // DevKit NCCH Secure4 key SHA256 90 | { 0xA5, 0x3C, 0x3E, 0x5D, 0x09, 0x5C, 0x73, 0x35, 0x21, 0x79, 0x3F, 0x2E, 0x4C, 0x10, 0xCA, 0xAE, 91 | 0x87, 0x83, 0x51, 0x53, 0x46, 0x0B, 0x52, 0x39, 0x9B, 0x00, 0x62, 0xF6, 0x39, 0xCB, 0x62, 0x16 } 92 | }*/ 93 | }; 94 | 95 | u8 keySha256[32]; 96 | sha_quick(keySha256, key, 16, SHA256_MODE); 97 | for (u32 p = 0; p < sizeof(keyHashes) / sizeof(AesKeyHashInfo); p++) { 98 | if ((keyHashes[p].desc.slot != keyslot) || (keyHashes[p].desc.type != type)) 99 | continue; 100 | if ((!id && keyHashes[p].desc.id[0]) || (id && strncmp(id, keyHashes[p].desc.id, 10) != 0)) 101 | continue; 102 | if (keyHashes[p].keyUnitType && (keyHashes[p].keyUnitType != GetUnitKeysType())) 103 | continue; 104 | if (memcmp(keySha256, keyHashes[p].keySha256, 32) == 0) { 105 | return 0; 106 | } 107 | } 108 | 109 | return 1; 110 | } 111 | 112 | u32 CheckKeySlot(u32 keyslot, char type) 113 | { 114 | static const AesNcchSampleInfo keyNcchSamples[] = { 115 | { 0x18, KEYS_RETAIL, // Retail NCCH Secure3 116 | { 0x78, 0xBB, 0x84, 0xFA, 0xB3, 0xA2, 0x49, 0x83, 0x9E, 0x4F, 0x50, 0x7B, 0x17, 0xA0, 0xDA, 0x23 } }, 117 | { 0x1B, KEYS_RETAIL, // Retail NCCH Secure4 118 | { 0xF3, 0x6F, 0x84, 0x7E, 0x59, 0x43, 0x6E, 0xD5, 0xA0, 0x40, 0x4C, 0x71, 0x19, 0xED, 0xF7, 0x0A } }, 119 | { 0x25, KEYS_RETAIL, // Retail NCCH 7x 120 | { 0x34, 0x7D, 0x07, 0x48, 0xAE, 0x5D, 0xFB, 0xB0, 0xF5, 0x86, 0xD6, 0xB5, 0x14, 0x65, 0xF1, 0xFF } }, 121 | { 0x18, KEYS_DEVKIT, // DevKit NCCH Secure3 122 | { 0x20, 0x8B, 0xB5, 0x61, 0x94, 0x18, 0x6A, 0x84, 0x91, 0xD6, 0x37, 0x27, 0x91, 0xF3, 0x53, 0xC9 } }, 123 | { 0x1B, KEYS_DEVKIT, // DevKit NCCH Secure4 124 | { 0xB3, 0x9D, 0xC1, 0xDB, 0x5B, 0x0C, 0xE7, 0x60, 0xBE, 0xAD, 0x5A, 0xBF, 0xD0, 0x86, 0x99, 0x88 } }, 125 | { 0x25, KEYS_DEVKIT, // DevKit NCCH 7x 126 | { 0xBC, 0x83, 0x7C, 0xC9, 0x99, 0xC8, 0x80, 0x9E, 0x8A, 0xDE, 0x4A, 0xFA, 0xAA, 0x72, 0x08, 0x28 } } 127 | }; 128 | u64* state = (type == 'X') ? &keyXState : (type == 'Y') ? &keyYState : (type == 'N') ? &keyState : NULL; 129 | 130 | // just to be safe... 131 | if (keyslot >= 0x40) 132 | return 1; 133 | 134 | // check if key is already loaded 135 | if ((type != 'I') && ((*state >> keyslot) & 1)) 136 | return 0; 137 | 138 | // if is not, we may still be able to verify the currently set one (for NCCH keys) 139 | for (u32 p = 0; (type == 'X') && (p < sizeof(keyNcchSamples) / sizeof(AesNcchSampleInfo)); p++) { 140 | if (keyNcchSamples[p].slot != keyslot) // only for keyslots in the keyNcchSamples table! 141 | continue; 142 | if (keyNcchSamples[p].keyUnitType && (keyNcchSamples[p].keyUnitType != GetUnitKeysType())) 143 | continue; 144 | u8 zeroes[16] = { 0 }; 145 | u8 sample[16] = { 0 }; 146 | setup_aeskeyY(keyslot, zeroes); 147 | use_aeskey(keyslot); 148 | set_ctr(zeroes); 149 | aes_decrypt(sample, sample, 1, AES_CNT_CTRNAND_MODE); 150 | if (memcmp(keyNcchSamples[p].sample, sample, 16) == 0) { 151 | keyXState |= (u64) 1 << keyslot; 152 | return 0; 153 | } 154 | } 155 | 156 | // not set up if getting here 157 | return 1; 158 | } 159 | 160 | u32 LoadKeyFromFile(u8* key, u32 keyslot, char type, char* id) 161 | { 162 | u8 keystore[16] __attribute__((aligned(32))) = {0}; 163 | bool found = false; 164 | FIL fp; 165 | UINT btr; 166 | 167 | // use keystore if key == NULL 168 | if (!key) key = keystore; 169 | 170 | // checking the obvious 171 | if ((keyslot >= 0x40) || ((type != 'X') && (type != 'Y') && (type != 'N') && (type != 'I'))) 172 | return 1; 173 | 174 | // check if already loaded 175 | if (!id && (CheckKeySlot(keyslot, type) == 0)) return 0; 176 | // try to get key from 'aeskeydb.bin' file 177 | AesKeyInfo info; 178 | if (f_open(&fp, PATH_KEYDB, FA_READ | FA_OPEN_EXISTING) == FR_OK) { 179 | while ((f_read(&fp, &info, sizeof(AesKeyInfo), &btr) == FR_OK) && (btr == sizeof(AesKeyInfo))) { 180 | if ((info.slot == keyslot) && (info.type == type) && 181 | ((!id && !(info.id[0])) || (id && (strncmp(id, info.id, 10) == 0))) && 182 | (!info.keyUnitType || (info.keyUnitType == GetUnitKeysType()))) { 183 | found = true; 184 | if (info.isEncrypted) 185 | CryptAesKeyInfo(&info); 186 | memcpy(key, info.key, 16); 187 | break; 188 | } 189 | } 190 | f_close(&fp); 191 | } 192 | 193 | // load legacy slot0x??Key?.bin file instead 194 | if (!found && (type != 'I')) { 195 | char path[64]; 196 | snprintf(path, 64, "%s/slot0x%02lXKey%s.bin", INPUT_PATH, keyslot, 197 | (id) ? id : (type == 'X') ? "X" : (type == 'Y') ? "Y" : ""); 198 | if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING) == FR_OK) { 199 | if ((f_read(&fp, key, 16, &btr) == FR_OK) && (btr == 16)) 200 | found = true; 201 | f_close(&fp); 202 | } 203 | } 204 | 205 | // key still not found (duh) 206 | if (!found) return 1; // out of options here 207 | 208 | // done if this is an IV 209 | if (type == 'I') return 0; 210 | 211 | // verify key (verification is disabled) 212 | // if (CheckAesKeyInfo(key, keyslot, type, id) != 0) return 1; 213 | 214 | // now, setup the key 215 | if (type == 'X') { 216 | setup_aeskeyX(keyslot, key); 217 | keyXState |= (u64) 1 << keyslot; 218 | } else if (type == 'Y') { 219 | setup_aeskeyY(keyslot, key); 220 | keyYState |= (u64) 1 << keyslot; 221 | } else { // normalKey includes keyX & keyY 222 | setup_aeskey(keyslot, key); 223 | keyState |= (u64) 1 << keyslot; 224 | keyXState |= (u64) 1 << keyslot; 225 | keyYState |= (u64) 1 << keyslot; 226 | } 227 | use_aeskey(keyslot); 228 | 229 | return 0; 230 | } 231 | -------------------------------------------------------------------------------- /source/crypto/keydb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | #define KEYDB_NAME "aeskeydb.bin" 6 | 7 | #define KEYS_UNKNOWN 0 8 | #define KEYS_DEVKIT 1 9 | #define KEYS_RETAIL 2 10 | 11 | typedef struct { 12 | u8 slot; // keyslot, 0x00...0x3F 13 | char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV 14 | char id[10]; // key ID for special keys, all zero for standard keys 15 | u8 reserved[2]; // reserved space 16 | u8 keyUnitType; // 0 for ALL units / 1 for retail exclusive / 2 for devkit exclusive 17 | u8 isEncrypted; // 0 if not / anything else if it is 18 | u8 key[16]; 19 | } __attribute__((packed)) AesKeyInfo; 20 | 21 | u32 GetUnitKeysType(void); 22 | void CryptAesKeyInfo(AesKeyInfo* info); 23 | u32 LoadKeyFromFile(u8* key, u32 keyslot, char type, char* id); 24 | -------------------------------------------------------------------------------- /source/crypto/sha.c: -------------------------------------------------------------------------------- 1 | #include "sha.h" 2 | 3 | void sha_init(u32 mode) 4 | { 5 | while(*REG_SHACNT & 1); 6 | *REG_SHACNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; 7 | } 8 | 9 | void sha_update(const void* src, u32 size) 10 | { 11 | const u32* src32 = (const u32*)src; 12 | 13 | while(size >= 0x40) { 14 | while(*REG_SHACNT & 1); 15 | for(u32 i = 0; i < 4; i++) { 16 | *REG_SHAINFIFO = *src32++; 17 | *REG_SHAINFIFO = *src32++; 18 | *REG_SHAINFIFO = *src32++; 19 | *REG_SHAINFIFO = *src32++; 20 | } 21 | size -= 0x40; 22 | } 23 | while(*REG_SHACNT & 1); 24 | memcpy((void*)REG_SHAINFIFO, src32, size); 25 | } 26 | 27 | void sha_get(void* res) { 28 | *REG_SHACNT = (*REG_SHACNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; 29 | while(*REG_SHACNT & SHA_FINAL_ROUND); 30 | while(*REG_SHACNT & 1); 31 | memcpy(res, (void*)REG_SHAHASH, (256 / 8)); 32 | } 33 | 34 | void sha_quick(void* res, const void* src, u32 size, u32 mode) { 35 | sha_init(mode); 36 | sha_update(src, size); 37 | sha_get(res); 38 | } 39 | 40 | int sha_cmp(const void* sha, const void* src, u32 size, u32 mode) { 41 | u8 res[0x20]; 42 | sha_quick(res, src, size, mode); 43 | return memcmp(sha, res, 0x20); 44 | } 45 | -------------------------------------------------------------------------------- /source/crypto/sha.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | #define REG_SHACNT ((volatile uint32_t*)0x1000A000) 6 | #define REG_SHABLKCNT ((volatile uint32_t*)0x1000A004) 7 | #define REG_SHAHASH ((volatile uint32_t*)0x1000A040) 8 | #define REG_SHAINFIFO ((volatile uint32_t*)0x1000A080) 9 | 10 | #define SHA_CNT_STATE 0x00000003 11 | #define SHA_CNT_OUTPUT_ENDIAN 0x00000008 12 | #define SHA_CNT_MODE 0x00000030 13 | #define SHA_CNT_ENABLE 0x00010000 14 | #define SHA_CNT_ACTIVE 0x00020000 15 | 16 | #define SHA_HASH_READY 0x00000000 17 | #define SHA_NORMAL_ROUND 0x00000001 18 | #define SHA_FINAL_ROUND 0x00000002 19 | 20 | #define SHA256_MODE 0 21 | #define SHA224_MODE 0x00000010 22 | #define SHA1_MODE 0x00000020 23 | 24 | 25 | void sha_init(u32 mode); 26 | void sha_update(const void* src, u32 size); 27 | void sha_get(void* res); 28 | void sha_quick(void* res, const void* src, u32 size, u32 mode); 29 | int sha_cmp(const void* sha, const void* src, u32 size, u32 mode); 30 | -------------------------------------------------------------------------------- /source/fatfs/00history.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | Revision history of FatFs module 3 | ---------------------------------------------------------------------------- 4 | 5 | R0.00 (February 26, 2006) 6 | 7 | Prototype. 8 | 9 | 10 | 11 | R0.01 (April 29, 2006) 12 | 13 | The first release. 14 | 15 | 16 | 17 | R0.02 (June 01, 2006) 18 | 19 | Added FAT12 support. 20 | Removed unbuffered mode. 21 | Fixed a problem on small (<32M) partition. 22 | 23 | 24 | 25 | R0.02a (June 10, 2006) 26 | 27 | Added a configuration option (_FS_MINIMUM). 28 | 29 | 30 | 31 | R0.03 (September 22, 2006) 32 | 33 | Added f_rename(). 34 | Changed option _FS_MINIMUM to _FS_MINIMIZE. 35 | 36 | 37 | 38 | R0.03a (December 11, 2006) 39 | 40 | Improved cluster scan algorithm to write files fast. 41 | Fixed f_mkdir() creates incorrect directory on FAT32. 42 | 43 | 44 | 45 | R0.04 (February 04, 2007) 46 | 47 | Added f_mkfs(). 48 | Supported multiple drive system. 49 | Changed some interfaces for multiple drive system. 50 | Changed f_mountdrv() to f_mount(). 51 | 52 | 53 | 54 | R0.04a (April 01, 2007) 55 | 56 | Supported multiple partitions on a physical drive. 57 | Added a capability of extending file size to f_lseek(). 58 | Added minimization level 3. 59 | Fixed an endian sensitive code in f_mkfs(). 60 | 61 | 62 | 63 | R0.04b (May 05, 2007) 64 | 65 | Added a configuration option _USE_NTFLAG. 66 | Added FSINFO support. 67 | Fixed DBCS name can result FR_INVALID_NAME. 68 | Fixed short seek (<= csize) collapses the file object. 69 | 70 | 71 | 72 | R0.05 (August 25, 2007) 73 | 74 | Changed arguments of f_read(), f_write() and f_mkfs(). 75 | Fixed f_mkfs() on FAT32 creates incorrect FSINFO. 76 | Fixed f_mkdir() on FAT32 creates incorrect directory. 77 | 78 | 79 | 80 | R0.05a (February 03, 2008) 81 | 82 | Added f_truncate() and f_utime(). 83 | Fixed off by one error at FAT sub-type determination. 84 | Fixed btr in f_read() can be mistruncated. 85 | Fixed cached sector is not flushed when create and close without write. 86 | 87 | 88 | 89 | R0.06 (April 01, 2008) 90 | 91 | Added fputc(), fputs(), fprintf() and fgets(). 92 | Improved performance of f_lseek() on moving to the same or following cluster. 93 | 94 | 95 | 96 | R0.07 (April 01, 2009) 97 | 98 | Merged Tiny-FatFs as a configuration option. (_FS_TINY) 99 | Added long file name feature. (_USE_LFN) 100 | Added multiple code page feature. (_CODE_PAGE) 101 | Added re-entrancy for multitask operation. (_FS_REENTRANT) 102 | Added auto cluster size selection to f_mkfs(). 103 | Added rewind option to f_readdir(). 104 | Changed result code of critical errors. 105 | Renamed string functions to avoid name collision. 106 | 107 | 108 | 109 | R0.07a (April 14, 2009) 110 | 111 | Septemberarated out OS dependent code on reentrant cfg. 112 | Added multiple sector size feature. 113 | 114 | 115 | 116 | R0.07c (June 21, 2009) 117 | 118 | Fixed f_unlink() can return FR_OK on error. 119 | Fixed wrong cache control in f_lseek(). 120 | Added relative path feature. 121 | Added f_chdir() and f_chdrive(). 122 | Added proper case conversion to extended character. 123 | 124 | 125 | 126 | R0.07e (November 03, 2009) 127 | 128 | Septemberarated out configuration options from ff.h to ffconf.h. 129 | Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. 130 | Fixed name matching error on the 13 character boundary. 131 | Added a configuration option, _LFN_UNICODE. 132 | Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. 133 | 134 | 135 | 136 | R0.08 (May 15, 2010) 137 | 138 | Added a memory configuration option. (_USE_LFN = 3) 139 | Added file lock feature. (_FS_SHARE) 140 | Added fast seek feature. (_USE_FASTSEEK) 141 | Changed some types on the API, XCHAR->TCHAR. 142 | Changed .fname in the FILINFO structure on Unicode cfg. 143 | String functions support UTF-8 encoding files on Unicode cfg. 144 | 145 | 146 | 147 | R0.08a (August 16, 2010) 148 | 149 | Added f_getcwd(). (_FS_RPATH = 2) 150 | Added sector erase feature. (_USE_ERASE) 151 | Moved file lock semaphore table from fs object to the bss. 152 | Fixed f_mkfs() creates wrong FAT32 volume. 153 | 154 | 155 | 156 | R0.08b (January 15, 2011) 157 | 158 | Fast seek feature is also applied to f_read() and f_write(). 159 | f_lseek() reports required table size on creating CLMP. 160 | Extended format syntax of f_printf(). 161 | Ignores duplicated directory separators in given path name. 162 | 163 | 164 | 165 | R0.09 (September 06, 2011) 166 | 167 | f_mkfs() supports multiple partition to complete the multiple partition feature. 168 | Added f_fdisk(). 169 | 170 | 171 | 172 | R0.09a (August 27, 2012) 173 | 174 | Changed f_open() and f_opendir() reject null object pointer to avoid crash. 175 | Changed option name _FS_SHARE to _FS_LOCK. 176 | Fixed assertion failure due to OS/2 EA on FAT12/16 volume. 177 | 178 | 179 | 180 | R0.09b (January 24, 2013) 181 | 182 | Added f_setlabel() and f_getlabel(). 183 | 184 | 185 | 186 | R0.10 (October 02, 2013) 187 | 188 | Added selection of character encoding on the file. (_STRF_ENCODE) 189 | Added f_closedir(). 190 | Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) 191 | Added forced mount feature with changes of f_mount(). 192 | Improved behavior of volume auto detection. 193 | Improved write throughput of f_puts() and f_printf(). 194 | Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). 195 | Fixed f_write() can be truncated when the file size is close to 4GB. 196 | Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. 197 | 198 | 199 | 200 | R0.10a (January 15, 2014) 201 | 202 | Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) 203 | Added a configuration option of minimum sector size. (_MIN_SS) 204 | 2nd argument of f_rename() can have a drive number and it will be ignored. 205 | Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) 206 | Fixed f_close() invalidates the file object without volume lock. 207 | Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) 208 | Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) 209 | 210 | 211 | 212 | R0.10b (May 19, 2014) 213 | 214 | Fixed a hard error in the disk I/O layer can collapse the directory entry. 215 | Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07) 216 | 217 | 218 | 219 | R0.10c (November 09, 2014) 220 | 221 | Added a configuration option for the platforms without RTC. (_FS_NORTC) 222 | Changed option name _USE_ERASE to _USE_TRIM. 223 | Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) 224 | Fixed a potential problem of FAT access that can appear on disk error. 225 | Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) 226 | 227 | 228 | 229 | R0.11 (February 09, 2015) 230 | 231 | Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) 232 | Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) 233 | Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) 234 | 235 | 236 | 237 | R0.11a (September 05, 2015) 238 | 239 | Fixed wrong media change can lead a deadlock at thread-safe configuration. 240 | Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) 241 | Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) 242 | Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). 243 | Fixed errors in the case conversion teble of Unicode (cc*.c). 244 | 245 | 246 | 247 | R0.12 (April 12, 2016) 248 | 249 | Added support for exFAT file system. (_FS_EXFAT) 250 | Added f_expand(). (_USE_EXPAND) 251 | Changed some members in FINFO structure and behavior of f_readdir(). 252 | Added an option _USE_CHMOD. 253 | Removed an option _WORD_ACCESS. 254 | Fixed errors in the case conversion table of Unicode (cc*.c). 255 | 256 | 257 | 258 | R0.12a (July 10, 2016) 259 | 260 | Added support for creating exFAT volume with some changes of f_mkfs(). 261 | Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. 262 | f_forward() is available regardless of _FS_TINY. 263 | Fixed f_mkfs() creates wrong volume. (appeared at R0.12) 264 | Fixed wrong memory read in create_name(). (appeared at R0.12) 265 | Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. 266 | 267 | 268 | 269 | R0.12b (September 04, 2016) 270 | 271 | Improved f_rename() to be able to rename objects with the same name but case. 272 | Fixed an error in the case conversion teble of code page 866. (ff.c) 273 | Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) 274 | Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) 275 | Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) 276 | Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) 277 | Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) 278 | Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) 279 | 280 | -------------------------------------------------------------------------------- /source/fatfs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.12a 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | history.txt Revision history. 8 | ffconf.h Configuration file for FatFs module. 9 | ff.h Common include file for FatFs and application module. 10 | ff.c FatFs module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | option Optional external functions. 15 | 16 | 17 | Low level disk I/O module is not included in this archive because the FatFs 18 | module is only a generic file system layer and not depend on any specific 19 | storage device. You have to provide a low level disk I/O module that written 20 | to control the target storage device. 21 | 22 | -------------------------------------------------------------------------------- /source/fatfs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various exsisting */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "diskio.h" /* FatFs lower layer API */ 11 | #include "nand.h" 12 | #include "sdmmc.h" 13 | 14 | 15 | #define PART_INFO(pdrv) (DriveInfo + pdrv) 16 | #define PART_TYPE(pdrv) (DriveInfo[pdrv].type) 17 | 18 | #define TYPE_NONE 0 19 | #define TYPE_SYSNAND (1UL<<0) 20 | #define TYPE_SDCARD (1UL<<4) 21 | 22 | #define SUBTYPE_CTRN 1 23 | #define SUBTYPE_TWLN 2 24 | #define SUBTYPE_TWLP 3 25 | #define SUBTYPE_NONE 0 26 | 27 | typedef struct { 28 | BYTE type; 29 | BYTE subtype; 30 | DWORD offset; 31 | DWORD size; 32 | BYTE keyslot; 33 | } FATpartition; 34 | 35 | FATpartition DriveInfo[13] = { 36 | { TYPE_SDCARD, SUBTYPE_NONE, 0, 0, 0xFF }, // 0 - SDCARD 37 | { TYPE_SYSNAND, SUBTYPE_CTRN, 0, 0, 0xFF }, // 1 - SYSNAND CTRNAND 38 | { TYPE_SYSNAND, SUBTYPE_TWLN, 0, 0, 0xFF }, // 2 - SYSNAND TWLN 39 | { TYPE_SYSNAND, SUBTYPE_TWLP, 0, 0, 0xFF }, // 3 - SYSNAND TWLP 40 | }; 41 | 42 | 43 | 44 | /*-----------------------------------------------------------------------*/ 45 | /* Get Drive Status */ 46 | /*-----------------------------------------------------------------------*/ 47 | 48 | DSTATUS disk_status ( 49 | __attribute__((unused)) 50 | BYTE pdrv /* Physical drive number to identify the drive */ 51 | ) 52 | { 53 | return RES_OK; 54 | } 55 | 56 | 57 | 58 | /*-----------------------------------------------------------------------*/ 59 | /* Initialize a Drive */ 60 | /*-----------------------------------------------------------------------*/ 61 | 62 | DSTATUS disk_initialize ( 63 | __attribute__((unused)) 64 | BYTE pdrv /* Physical drive number to identify the drive */ 65 | ) 66 | { 67 | FATpartition* fat_info = PART_INFO(pdrv); 68 | BYTE type = PART_TYPE(pdrv); 69 | 70 | fat_info->offset = fat_info->size = 0; 71 | fat_info->keyslot = 0xFF; 72 | 73 | if (type == TYPE_SDCARD) { 74 | if (sdmmc_sdcard_init() != 0) return STA_NOINIT|STA_NODISK; 75 | fat_info->size = getMMCDevice(1)->total_size; 76 | } else if (type == TYPE_SYSNAND) { 77 | NandPartitionInfo nprt_info; 78 | if ((fat_info->subtype == SUBTYPE_CTRN) && 79 | (GetNandPartitionInfo(&nprt_info, NP_TYPE_STD, NP_SUBTYPE_CTR, 0) != 0) && 80 | (GetNandPartitionInfo(&nprt_info, NP_TYPE_STD, NP_SUBTYPE_CTR_N, 0) != 0)) { 81 | return STA_NOINIT|STA_NODISK; 82 | } else if ((fat_info->subtype == SUBTYPE_TWLN) && 83 | (GetNandPartitionInfo(&nprt_info, NP_TYPE_FAT, NP_SUBTYPE_TWL, 0) != 0)) { 84 | return STA_NOINIT|STA_NODISK; 85 | } else if ((fat_info->subtype == SUBTYPE_TWLP) && 86 | (GetNandPartitionInfo(&nprt_info, NP_TYPE_FAT, NP_SUBTYPE_TWL, 1) != 0)) { 87 | return STA_NOINIT|STA_NODISK; 88 | } 89 | fat_info->offset = nprt_info.sector; 90 | fat_info->size = nprt_info.count; 91 | fat_info->keyslot = nprt_info.keyslot; 92 | } 93 | 94 | return RES_OK; 95 | } 96 | 97 | 98 | 99 | /*-----------------------------------------------------------------------*/ 100 | /* Read Sector(s) */ 101 | /*-----------------------------------------------------------------------*/ 102 | 103 | DRESULT disk_read ( 104 | __attribute__((unused)) 105 | BYTE pdrv, /* Physical drive number to identify the drive */ 106 | BYTE *buff, /* Data buffer to store read data */ 107 | DWORD sector, /* Sector address in LBA */ 108 | UINT count /* Number of sectors to read */ 109 | ) 110 | { 111 | BYTE type = PART_TYPE(pdrv); 112 | 113 | if (type == TYPE_NONE) { 114 | return RES_PARERR; 115 | } else if (type == TYPE_SDCARD) { 116 | if (sdmmc_sdcard_readsectors(sector, count, buff)) 117 | return RES_PARERR; 118 | } else { 119 | FATpartition* fat_info = PART_INFO(pdrv); 120 | if (ReadNandSectors(buff, fat_info->offset + sector, count, fat_info->keyslot)) 121 | return RES_PARERR; 122 | } 123 | 124 | return RES_OK; 125 | } 126 | 127 | 128 | 129 | /*-----------------------------------------------------------------------*/ 130 | /* Write Sector(s) */ 131 | /*-----------------------------------------------------------------------*/ 132 | 133 | #if _USE_WRITE 134 | DRESULT disk_write ( 135 | __attribute__((unused)) 136 | BYTE pdrv, /* Physical drive number to identify the drive */ 137 | const BYTE *buff, /* Data to be written */ 138 | DWORD sector, /* Sector address in LBA */ 139 | UINT count /* Number of sectors to write */ 140 | ) 141 | { 142 | BYTE type = PART_TYPE(pdrv); 143 | 144 | if (type == TYPE_NONE) { 145 | return RES_PARERR; 146 | } else if (type == TYPE_SDCARD) { 147 | if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) 148 | return RES_PARERR; 149 | } else { 150 | FATpartition* fat_info = PART_INFO(pdrv); 151 | if (WriteNandSectors(buff, fat_info->offset + sector, count, fat_info->keyslot)) 152 | return RES_PARERR; // unstubbed! 153 | } 154 | 155 | return RES_OK; 156 | } 157 | #endif 158 | 159 | 160 | 161 | /*-----------------------------------------------------------------------*/ 162 | /* Miscellaneous Functions */ 163 | /*-----------------------------------------------------------------------*/ 164 | 165 | #if _USE_IOCTL 166 | DRESULT disk_ioctl ( 167 | __attribute__((unused)) 168 | BYTE pdrv, /* Physical drive number (0..) */ 169 | __attribute__((unused)) 170 | BYTE cmd, /* Control code */ 171 | __attribute__((unused)) 172 | void *buff /* Buffer to send/receive control data */ 173 | ) 174 | { 175 | switch (cmd) { 176 | case GET_SECTOR_SIZE: 177 | *((DWORD*) buff) = 0x200; 178 | return RES_OK; 179 | case GET_SECTOR_COUNT: 180 | *((DWORD*) buff) = PART_INFO(pdrv)->size; 181 | return RES_OK; 182 | case GET_BLOCK_SIZE: 183 | *((DWORD*) buff) = 0x2000; 184 | return RES_OK; 185 | case CTRL_SYNC: 186 | // nothing else to do here - sdmmc.c handles the rest 187 | return RES_OK; 188 | } 189 | 190 | return RES_PARERR; 191 | } 192 | #endif 193 | -------------------------------------------------------------------------------- /source/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define _USE_WRITE 1 /* 1: Enable disk_write function */ 13 | #define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ 14 | 15 | #include "integer.h" 16 | 17 | 18 | /* Status of Disk Functions */ 19 | typedef BYTE DSTATUS; 20 | 21 | /* Results of Disk Functions */ 22 | typedef enum { 23 | RES_OK = 0, /* 0: Successful */ 24 | RES_ERROR, /* 1: R/W Error */ 25 | RES_WRPRT, /* 2: Write Protected */ 26 | RES_NOTRDY, /* 3: Not Ready */ 27 | RES_PARERR /* 4: Invalid Parameter */ 28 | } DRESULT; 29 | 30 | 31 | /*---------------------------------------*/ 32 | /* Prototypes for disk control functions */ 33 | 34 | 35 | DSTATUS disk_initialize (BYTE pdrv); 36 | DSTATUS disk_status (BYTE pdrv); 37 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 38 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 39 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 40 | 41 | 42 | /* Disk Status Bits (DSTATUS) */ 43 | 44 | #define STA_NOINIT 0x01 /* Drive not initialized */ 45 | #define STA_NODISK 0x02 /* No medium in the drive */ 46 | #define STA_PROTECT 0x04 /* Write protected */ 47 | 48 | 49 | /* Command code for disk_ioctrl fucntion */ 50 | 51 | /* Generic command (Used by FatFs) */ 52 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 53 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 54 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 55 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 56 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 57 | 58 | /* Generic command (Not used by FatFs) */ 59 | #define CTRL_POWER 5 /* Get/Set power status */ 60 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 61 | #define CTRL_EJECT 7 /* Eject media */ 62 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 63 | 64 | /* MMC/SDC specific ioctl command */ 65 | #define MMC_GET_TYPE 10 /* Get card type */ 66 | #define MMC_GET_CSD 11 /* Get CSD */ 67 | #define MMC_GET_CID 12 /* Get CID */ 68 | #define MMC_GET_OCR 13 /* Get OCR */ 69 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 70 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 71 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 72 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 73 | 74 | /* ATA/CF specific ioctl command */ 75 | #define ATA_GET_REV 20 /* Get F/W revision */ 76 | #define ATA_GET_MODEL 21 /* Get model name */ 77 | #define ATA_GET_SN 22 /* Get serial number */ 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /source/fatfs/fatmbr.c: -------------------------------------------------------------------------------- 1 | #include "fatmbr.h" 2 | 3 | u32 ValidateMbrHeader(MbrHeader* mbr) { 4 | if (mbr->magic != FATMBR_MAGIC) return 1; // check magic 5 | u32 sector = 1; // check partitions 6 | for (u32 i = 0; i < 4; i++) { 7 | MbrPartitionInfo* partition = mbr->partitions + i; 8 | if (!partition->count && i) continue; 9 | else if (!partition->count) return 1; // first partition can't be empty 10 | if ((partition->type != 0x1) && (partition->type != 0x4) && (partition->type != 0x6) && 11 | (partition->type != 0xB) && (partition->type != 0xC) && (partition->type != 0xE)) 12 | return 1; // bad / unknown filesystem type 13 | if (partition->sector < sector) return 1; // overlapping partitions 14 | sector = partition->sector + partition->count; 15 | } 16 | return 0; 17 | } 18 | 19 | u32 ValidateFatHeader(void* fat) { 20 | if (getle16((u8*) fat + 0x1FE) != FATMBR_MAGIC) return 1; // check magic 21 | Fat32Header* fat32 = (Fat32Header*) fat; 22 | if (strncmp(fat32->fs_type, "FAT32 ", 8) == 0) 23 | return 0; // is FAT32 header 24 | Fat16Header* fat16 = (Fat16Header*) fat; 25 | if ((strncmp(fat16->fs_type, "FAT16 ", 8) == 0) || 26 | (strncmp(fat16->fs_type, "FAT12 ", 8) == 0) || 27 | (strncmp(fat16->fs_type, "FAT ", 8) == 0)) 28 | return 0; // is FAT16 / FAT12 header 29 | if ((getle64(fat16->fs_type) == 0) && (fat16->sct_size == 0x200)) 30 | return 0; // special case for public.sav 31 | return 1; // failed, not a FAT header 32 | } 33 | -------------------------------------------------------------------------------- /source/fatfs/fatmbr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | #define FATMBR_MAGIC 0xAA55 // little endian! 6 | 7 | typedef struct { 8 | u8 status; // 0x80 9 | u8 chs_start[3]; // 0x01 0x01 0x00 10 | u8 type; // 0x0C 11 | u8 chs_end[3]; // 0xFE 0xFF 0xFF 12 | u32 sector; // 0x2000 (4MB offset, 512 byte sectors) 13 | u32 count; 14 | } __attribute__((packed)) MbrPartitionInfo; 15 | 16 | typedef struct { 17 | char text[446]; 18 | MbrPartitionInfo partitions[4]; 19 | u16 magic; // 0xAA55 20 | } __attribute__((packed)) MbrHeader; 21 | 22 | typedef struct { // unused 23 | u32 signature0; // 0x41615252 24 | u8 reserved0[480]; 25 | u32 signature1; // 0x61417272 26 | u32 clr_free; // 0xFFFFFFFF 27 | u32 clr_next; // 0xFFFFFFFF 28 | u8 reserved1[14]; 29 | u16 magic; // 0xAA55 30 | } __attribute__((packed)) FileSystemInfo; 31 | 32 | typedef struct { 33 | u8 jmp[3]; // 0x90 0x00 0xEB 34 | char oemname[8]; // "anything" 35 | u16 sct_size; // 0x0200 36 | u8 clr_size; // 0x40 -> 32kB clusters with 512byte sectors 37 | u16 sct_reserved; // 0x20 38 | u8 fat_n; // 0x02 39 | u16 reserved0; // root entry count in FAT16 40 | u16 reserved1; // partition size when <= 32MB 41 | u8 mediatype; // 0xF8 42 | u16 reserved2; // FAT size in sectors in FAT16 43 | u16 sct_track; // 0x3F 44 | u16 sct_heads; // 0xFF 45 | u32 sct_hidden; // same as partition offset in MBR 46 | u32 sct_total; // same as partition size in MBR 47 | u32 fat_size; // roundup((((sct_total - sct_reserved) / clr_size) * 4) / sct_size) 48 | u16 flags; // 0x00 49 | u16 version; // 0x00 50 | u32 clr_root; // 0x02 51 | u16 sct_fsinfo; // 0x01 52 | u16 sct_backup; // 0x06 53 | u8 reserved3[12]; 54 | u8 ndrive; // 0x80 55 | u8 head_cur; // 0x00 56 | u8 boot_sig; // 0x29 57 | u32 vol_id; // volume id / 0x00 58 | char vol_label[11]; // "anything " 59 | char fs_type[8]; // "FAT32 " 60 | u8 reserved4[420]; 61 | u16 magic; // 0xAA55 62 | } __attribute__((packed)) Fat32Header; 63 | 64 | typedef struct { // this struct is not tested enough! 65 | u8 jmp[3]; // 0x90 0x00 0xEB 66 | char oemname[8]; // "anything" 67 | u16 sct_size; // 0x0200 68 | u8 clr_size; // 0x20 (???) -> 16kB clusters with 512byte sectors 69 | u16 sct_reserved; // 0x01 70 | u8 fat_n; // 0x02 71 | u16 root_n; // 0x0200 72 | u16 reserved0; // partition size when <= 32MB 73 | u8 mediatype; // 0xF8 74 | u16 fat_size; // roundup((((sct_total - sct_reserved) / clr_size) * 2) / sct_size) 75 | u16 sct_track; // 0x3F 76 | u16 sct_heads; // 0xFF 77 | u32 sct_hidden; // same as partition offset in MBR 78 | u32 sct_total; // same as partition size in MBR 79 | u8 ndrive; // 0x80 80 | u8 head_cur; // 0x00 81 | u8 boot_sig; // 0x29 82 | u32 vol_id; // volume id / 0x00 83 | char vol_label[11]; // "anything " 84 | char fs_type[8]; // "FAT16 " 85 | u8 reserved4[448]; 86 | u16 magic; // 0xAA55 87 | } __attribute__((packed)) Fat16Header; 88 | 89 | u32 ValidateMbrHeader(MbrHeader* mbr); 90 | u32 ValidateFatHeader(void* fat); 91 | -------------------------------------------------------------------------------- /source/fatfs/ff.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / FatFs - Generic FAT file system module R0.12b / 3 | /-----------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2016, ChaN, all right reserved. 6 | / 7 | / FatFs module is an open source software. Redistribution and use of FatFs in 8 | / source and binary forms, with or without modification, are permitted provided 9 | / that the following condition is met: 10 | 11 | / 1. Redistributions of source code must retain the above copyright notice, 12 | / this condition and the following disclaimer. 13 | / 14 | / This software is provided by the copyright holder and contributors "AS IS" 15 | / and any warranties related to this software are DISCLAIMED. 16 | / The copyright owner or contributors be NOT LIABLE for any damages caused 17 | / by use of this software. 18 | /----------------------------------------------------------------------------*/ 19 | 20 | 21 | #ifndef _FATFS 22 | #define _FATFS 68020 /* Revision ID */ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #include "integer.h" /* Basic integer types */ 29 | #include "ffconf.h" /* FatFs configuration options */ 30 | 31 | #if _FATFS != _FFCONF 32 | #error Wrong configuration file (ffconf.h). 33 | #endif 34 | 35 | 36 | 37 | /* Definitions of volume management */ 38 | 39 | #if _MULTI_PARTITION /* Multiple partition configuration */ 40 | typedef struct { 41 | BYTE pd; /* Physical drive number */ 42 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 43 | } PARTITION; 44 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ 45 | #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ 46 | #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ 47 | 48 | #else /* Single partition configuration */ 49 | #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ 50 | #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ 51 | 52 | #endif 53 | 54 | 55 | 56 | /* Type of path name strings on FatFs API */ 57 | 58 | #if _LFN_UNICODE /* Unicode (UTF-16) string */ 59 | #if _USE_LFN == 0 60 | #error _LFN_UNICODE must be 0 at non-LFN cfg. 61 | #endif 62 | #ifndef _INC_TCHAR 63 | typedef WCHAR TCHAR; 64 | #define _T(x) L ## x 65 | #define _TEXT(x) L ## x 66 | #endif 67 | #else /* ANSI/OEM string */ 68 | #ifndef _INC_TCHAR 69 | typedef char TCHAR; 70 | #define _T(x) x 71 | #define _TEXT(x) x 72 | #endif 73 | #endif 74 | 75 | 76 | 77 | /* Type of file size variables */ 78 | 79 | #if _FS_EXFAT 80 | #if _USE_LFN == 0 81 | #error LFN must be enabled when enable exFAT 82 | #endif 83 | typedef QWORD FSIZE_t; 84 | #else 85 | typedef DWORD FSIZE_t; 86 | #endif 87 | 88 | 89 | 90 | /* File system object structure (FATFS) */ 91 | 92 | typedef struct { 93 | BYTE fs_type; /* File system type (0:N/A) */ 94 | BYTE drv; /* Physical drive number */ 95 | BYTE n_fats; /* Number of FATs (1 or 2) */ 96 | BYTE wflag; /* win[] flag (b0:dirty) */ 97 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 98 | WORD id; /* File system mount ID */ 99 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 100 | WORD csize; /* Cluster size [sectors] */ 101 | #if _MAX_SS != _MIN_SS 102 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ 103 | #endif 104 | #if _USE_LFN != 0 105 | WCHAR* lfnbuf; /* LFN working buffer */ 106 | #endif 107 | #if _FS_EXFAT 108 | BYTE* dirbuf; /* Directory entry block scratchpad buffer */ 109 | #endif 110 | #if _FS_REENTRANT 111 | _SYNC_t sobj; /* Identifier of sync object */ 112 | #endif 113 | #if !_FS_READONLY 114 | DWORD last_clst; /* Last allocated cluster */ 115 | DWORD free_clst; /* Number of free clusters */ 116 | #endif 117 | #if _FS_RPATH != 0 118 | DWORD cdir; /* Current directory start cluster (0:root) */ 119 | #if _FS_EXFAT 120 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ 121 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ 122 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ 123 | #endif 124 | #endif 125 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ 126 | DWORD fsize; /* Size of an FAT [sectors] */ 127 | DWORD volbase; /* Volume base sector */ 128 | DWORD fatbase; /* FAT base sector */ 129 | DWORD dirbase; /* Root directory base sector/cluster */ 130 | DWORD database; /* Data base sector */ 131 | DWORD winsect; /* Current sector appearing in the win[] */ 132 | BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 133 | } FATFS; 134 | 135 | 136 | 137 | /* Object ID and allocation information (_FDID) */ 138 | 139 | typedef struct { 140 | FATFS* fs; /* Pointer to the owner file system object */ 141 | WORD id; /* Owner file system mount ID */ 142 | BYTE attr; /* Object attribute */ 143 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ 144 | DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ 145 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */ 146 | #if _FS_EXFAT 147 | DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ 148 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ 149 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ 150 | DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ 151 | #endif 152 | #if _FS_LOCK != 0 153 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 154 | #endif 155 | } _FDID; 156 | 157 | 158 | 159 | /* File object structure (FIL) */ 160 | 161 | typedef struct { 162 | _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ 163 | BYTE flag; /* File status flags */ 164 | BYTE err; /* Abort flag (error code) */ 165 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ 166 | DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ 167 | DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ 168 | #if !_FS_READONLY 169 | DWORD dir_sect; /* Sector number containing the directory entry */ 170 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ 171 | #endif 172 | #if _USE_FASTSEEK 173 | DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ 174 | #endif 175 | #if !_FS_TINY 176 | BYTE buf[_MAX_SS]; /* File private data read/write window */ 177 | #endif 178 | } FIL; 179 | 180 | 181 | 182 | /* Directory object structure (DIR) */ 183 | 184 | typedef struct { 185 | _FDID obj; /* Object identifier */ 186 | DWORD dptr; /* Current read/write offset */ 187 | DWORD clust; /* Current cluster */ 188 | DWORD sect; /* Current sector */ 189 | BYTE* dir; /* Pointer to the directory item in the win[] */ 190 | BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ 191 | #if _USE_LFN != 0 192 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ 193 | #endif 194 | #if _USE_FIND 195 | const TCHAR* pat; /* Pointer to the name matching pattern */ 196 | #endif 197 | } DIR; 198 | 199 | 200 | 201 | /* File information structure (FILINFO) */ 202 | 203 | typedef struct { 204 | FSIZE_t fsize; /* File size */ 205 | WORD fdate; /* Modified date */ 206 | WORD ftime; /* Modified time */ 207 | BYTE fattrib; /* File attribute */ 208 | #if _USE_LFN != 0 209 | TCHAR altname[13]; /* Altenative file name */ 210 | TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ 211 | #else 212 | TCHAR fname[13]; /* File name */ 213 | #endif 214 | } FILINFO; 215 | 216 | 217 | 218 | /* File function return code (FRESULT) */ 219 | 220 | typedef enum { 221 | FR_OK = 0, /* (0) Succeeded */ 222 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 223 | FR_INT_ERR, /* (2) Assertion failed */ 224 | FR_NOT_READY, /* (3) The physical drive cannot work */ 225 | FR_NO_FILE, /* (4) Could not find the file */ 226 | FR_NO_PATH, /* (5) Could not find the path */ 227 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 228 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 229 | FR_EXIST, /* (8) Access denied due to prohibited access */ 230 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 231 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 232 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 233 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 234 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 235 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ 236 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 237 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 238 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 239 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ 240 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 241 | } FRESULT; 242 | 243 | 244 | 245 | /*--------------------------------------------------------------*/ 246 | /* FatFs module application interface */ 247 | 248 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 249 | FRESULT f_close (FIL* fp); /* Close an open file object */ 250 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ 251 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ 252 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ 253 | FRESULT f_truncate (FIL* fp); /* Truncate the file */ 254 | FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ 255 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 256 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 257 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 258 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 259 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 260 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 261 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 262 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 263 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 264 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ 265 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ 266 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 267 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 268 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 269 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 270 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 271 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 272 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 273 | FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ 274 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 275 | FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ 276 | FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ 277 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 278 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 279 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 280 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 281 | 282 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) 283 | #define f_error(fp) ((fp)->err) 284 | #define f_tell(fp) ((fp)->fptr) 285 | #define f_size(fp) ((fp)->obj.objsize) 286 | #define f_rewind(fp) f_lseek((fp), 0) 287 | #define f_rewinddir(dp) f_readdir((dp), 0) 288 | 289 | #ifndef EOF 290 | #define EOF (-1) 291 | #endif 292 | 293 | 294 | 295 | 296 | /*--------------------------------------------------------------*/ 297 | /* Additional user defined functions */ 298 | 299 | /* RTC function */ 300 | #if !_FS_READONLY && !_FS_NORTC 301 | DWORD get_fattime (void); 302 | #endif 303 | 304 | /* Unicode support functions */ 305 | #if _USE_LFN != 0 /* Unicode - OEM code conversion */ 306 | WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ 307 | WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ 308 | #if _USE_LFN == 3 /* Memory functions */ 309 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 310 | void ff_memfree (void* mblock); /* Free memory block */ 311 | #endif 312 | #endif 313 | 314 | /* Sync functions */ 315 | #if _FS_REENTRANT 316 | int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ 317 | int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ 318 | void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ 319 | int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ 320 | #endif 321 | 322 | 323 | 324 | 325 | /*--------------------------------------------------------------*/ 326 | /* Flags and offset address */ 327 | 328 | 329 | /* File access mode and open method flags (3rd argument of f_open) */ 330 | #define FA_READ 0x01 331 | #define FA_WRITE 0x02 332 | #define FA_OPEN_EXISTING 0x00 333 | #define FA_CREATE_NEW 0x04 334 | #define FA_CREATE_ALWAYS 0x08 335 | #define FA_OPEN_ALWAYS 0x10 336 | #define FA_OPEN_APPEND 0x30 337 | 338 | /* Fast seek controls (2nd argument of f_lseek) */ 339 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1) 340 | 341 | /* Format options (2nd argument of f_mkfs) */ 342 | #define FM_FAT 0x01 343 | #define FM_FAT32 0x02 344 | #define FM_EXFAT 0x04 345 | #define FM_ANY 0x07 346 | #define FM_SFD 0x08 347 | 348 | /* Filesystem type (FATFS.fs_type) */ 349 | #define FS_FAT12 1 350 | #define FS_FAT16 2 351 | #define FS_FAT32 3 352 | #define FS_EXFAT 4 353 | 354 | /* File attribute bits for directory entry (FILINFO.fattrib) */ 355 | #define AM_RDO 0x01 /* Read only */ 356 | #define AM_HID 0x02 /* Hidden */ 357 | #define AM_SYS 0x04 /* System */ 358 | #define AM_DIR 0x10 /* Directory */ 359 | #define AM_ARC 0x20 /* Archive */ 360 | 361 | 362 | #ifdef __cplusplus 363 | } 364 | #endif 365 | 366 | #endif /* _FATFS */ 367 | -------------------------------------------------------------------------------- /source/fatfs/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - FAT file system module configuration file 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define _FFCONF 68020 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define _FS_READONLY 0 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | 18 | #define _FS_MINIMIZE 0 19 | /* This option defines minimization level to remove some basic API functions. 20 | / 21 | / 0: All basic functions are enabled. 22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 23 | / are removed. 24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 25 | / 3: f_lseek() function is removed in addition to 2. */ 26 | 27 | 28 | #define _USE_STRFUNC 0 29 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and 30 | / f_printf(). 31 | / 32 | / 0: Disable string functions. 33 | / 1: Enable without LF-CRLF conversion. 34 | / 2: Enable with LF-CRLF conversion. */ 35 | 36 | 37 | #define _USE_FIND 0 38 | /* This option switches filtered directory read functions, f_findfirst() and 39 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 40 | 41 | 42 | #define _USE_MKFS 0 43 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 44 | 45 | 46 | #define _USE_FASTSEEK 0 47 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 48 | 49 | 50 | #define _USE_EXPAND 0 51 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 52 | 53 | 54 | #define _USE_CHMOD 0 55 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 56 | / (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ 57 | 58 | 59 | #define _USE_LABEL 1 60 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 61 | / (0:Disable or 1:Enable) */ 62 | 63 | 64 | #define _USE_FORWARD 0 65 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 66 | 67 | 68 | /*---------------------------------------------------------------------------/ 69 | / Locale and Namespace Configurations 70 | /---------------------------------------------------------------------------*/ 71 | 72 | #define _CODE_PAGE 437 73 | /* This option specifies the OEM code page to be used on the target system. 74 | / Incorrect setting of the code page can cause a file open failure. 75 | / 76 | / 1 - ASCII (No extended character. Non-LFN cfg. only) 77 | / 437 - U.S. 78 | / 720 - Arabic 79 | / 737 - Greek 80 | / 771 - KBL 81 | / 775 - Baltic 82 | / 850 - Latin 1 83 | / 852 - Latin 2 84 | / 855 - Cyrillic 85 | / 857 - Turkish 86 | / 860 - Portuguese 87 | / 861 - Icelandic 88 | / 862 - Hebrew 89 | / 863 - Canadian French 90 | / 864 - Arabic 91 | / 865 - Nordic 92 | / 866 - Russian 93 | / 869 - Greek 2 94 | / 932 - Japanese (DBCS) 95 | / 936 - Simplified Chinese (DBCS) 96 | / 949 - Korean (DBCS) 97 | / 950 - Traditional Chinese (DBCS) 98 | */ 99 | 100 | 101 | #define _USE_LFN 2 102 | #define _MAX_LFN 255 103 | /* The _USE_LFN switches the support of long file name (LFN). 104 | / 105 | / 0: Disable support of LFN. _MAX_LFN has no effect. 106 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 107 | / 2: Enable LFN with dynamic working buffer on the STACK. 108 | / 3: Enable LFN with dynamic working buffer on the HEAP. 109 | / 110 | / To enable the LFN, Unicode handling functions (option/unicode.c) must be added 111 | / to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and 112 | / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. 113 | / It should be set 255 to support full featured LFN operations. 114 | / When use stack for the working buffer, take care on stack overflow. When use heap 115 | / memory for the working buffer, memory management functions, ff_memalloc() and 116 | / ff_memfree(), must be added to the project. */ 117 | 118 | 119 | #define _LFN_UNICODE 0 120 | /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) 121 | / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. 122 | / This option also affects behavior of string I/O functions. */ 123 | 124 | 125 | #define _STRF_ENCODE 0 126 | /* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to 127 | / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). 128 | / 129 | / 0: ANSI/OEM 130 | / 1: UTF-16LE 131 | / 2: UTF-16BE 132 | / 3: UTF-8 133 | / 134 | / This option has no effect when _LFN_UNICODE == 0. */ 135 | 136 | 137 | #define _FS_RPATH 0 138 | /* This option configures support of relative path. 139 | / 140 | / 0: Disable relative path and remove related functions. 141 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 142 | / 2: f_getcwd() function is available in addition to 1. 143 | */ 144 | 145 | 146 | /*---------------------------------------------------------------------------/ 147 | / Drive/Volume Configurations 148 | /---------------------------------------------------------------------------*/ 149 | 150 | #define _VOLUMES 10 151 | /* Number of volumes (logical drives) to be used. */ 152 | 153 | 154 | #define _STR_VOLUME_ID 0 155 | #define _VOLUME_STRS "sdcard","sysnand","systwln","systwlp","emunand","emutwln","emutwlp","imgnand","imgtwln","imgtwlp" 156 | /* _STR_VOLUME_ID switches string support of volume ID. 157 | / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive 158 | / number in the path name. _VOLUME_STRS defines the drive ID strings for each 159 | / logical drives. Number of items must be equal to _VOLUMES. Valid characters for 160 | / the drive ID strings are: A-Z and 0-9. */ 161 | 162 | 163 | #define _MULTI_PARTITION 0 164 | /* This option switches support of multi-partition on a physical drive. 165 | / By default (0), each logical drive number is bound to the same physical drive 166 | / number and only an FAT volume found on the physical drive will be mounted. 167 | / When multi-partition is enabled (1), each logical drive number can be bound to 168 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 169 | / funciton will be available. */ 170 | 171 | 172 | #define _MIN_SS 512 173 | #define _MAX_SS 512 174 | /* These options configure the range of sector size to be supported. (512, 1024, 175 | / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and 176 | / harddisk. But a larger value may be required for on-board flash memory and some 177 | / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured 178 | / to variable sector size and GET_SECTOR_SIZE command must be implemented to the 179 | / disk_ioctl() function. */ 180 | 181 | 182 | #define _USE_TRIM 0 183 | /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) 184 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 185 | / disk_ioctl() function. */ 186 | 187 | 188 | #define _FS_NOFSINFO 0 189 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 190 | / option, and f_getfree() function at first time after volume mount will force 191 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 192 | / 193 | / bit0=0: Use free cluster count in the FSINFO if available. 194 | / bit0=1: Do not trust free cluster count in the FSINFO. 195 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 196 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 197 | */ 198 | 199 | 200 | 201 | /*---------------------------------------------------------------------------/ 202 | / System Configurations 203 | /---------------------------------------------------------------------------*/ 204 | 205 | #define _FS_TINY 0 206 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 207 | / At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. 208 | / Instead of private sector buffer eliminated from the file object, common sector 209 | / buffer in the file system object (FATFS) is used for the file data transfer. */ 210 | 211 | 212 | #define _FS_EXFAT 0 213 | /* This option switches support of exFAT file system. (0:Disable or 1:Enable) 214 | / When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) 215 | / Note that enabling exFAT discards C89 compatibility. */ 216 | 217 | 218 | #define _FS_NORTC 1 219 | #define _NORTC_MON 1 220 | #define _NORTC_MDAY 1 221 | #define _NORTC_YEAR 2016 222 | /* The option _FS_NORTC switches timestamp functiton. If the system does not have 223 | / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable 224 | / the timestamp function. All objects modified by FatFs will have a fixed timestamp 225 | / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. 226 | / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be 227 | / added to the project to get current time form real-time clock. _NORTC_MON, 228 | / _NORTC_MDAY and _NORTC_YEAR have no effect. 229 | / These options have no effect at read-only configuration (_FS_READONLY = 1). */ 230 | 231 | 232 | #define _FS_LOCK 32 233 | /* The option _FS_LOCK switches file lock function to control duplicated file open 234 | / and illegal operation to open objects. This option must be 0 when _FS_READONLY 235 | / is 1. 236 | / 237 | / 0: Disable file lock function. To avoid volume corruption, application program 238 | / should avoid illegal open, remove and rename to the open objects. 239 | / >0: Enable file lock function. The value defines how many files/sub-directories 240 | / can be opened simultaneously under file lock control. Note that the file 241 | / lock control is independent of re-entrancy. */ 242 | 243 | 244 | #define _FS_REENTRANT 0 245 | #define _FS_TIMEOUT 1000 246 | #define _SYNC_t HANDLE 247 | /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 248 | / module itself. Note that regardless of this option, file access to different 249 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 250 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 251 | / to the same volume is under control of this function. 252 | / 253 | / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. 254 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 255 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 256 | / function, must be added to the project. Samples are available in 257 | / option/syscall.c. 258 | / 259 | / The _FS_TIMEOUT defines timeout period in unit of time tick. 260 | / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 261 | / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be 262 | / included somewhere in the scope of ff.h. */ 263 | 264 | /* #include // O/S definitions */ 265 | 266 | 267 | /*--- End of configuration options ---*/ 268 | -------------------------------------------------------------------------------- /source/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _FF_INTEGER 6 | #define _FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for C89 compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /source/fatfs/option/syscall.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample code of OS dependent controls for FatFs */ 3 | /* (C)ChaN, 2014 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "../ff.h" 8 | 9 | 10 | #if _FS_REENTRANT 11 | /*------------------------------------------------------------------------*/ 12 | /* Create a Synchronization Object 13 | /*------------------------------------------------------------------------*/ 14 | /* This function is called in f_mount() function to create a new 15 | / synchronization object, such as semaphore and mutex. When a 0 is returned, 16 | / the f_mount() function fails with FR_INT_ERR. 17 | */ 18 | 19 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 20 | BYTE vol, /* Corresponding volume (logical drive number) */ 21 | _SYNC_t *sobj /* Pointer to return the created sync object */ 22 | ) 23 | { 24 | int ret; 25 | 26 | 27 | *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */ 28 | ret = (int)(*sobj != INVALID_HANDLE_VALUE); 29 | 30 | // *sobj = SyncObjects[vol]; /* uITRON (give a static sync object) */ 31 | // ret = 1; /* The initial value of the semaphore must be 1. */ 32 | 33 | // *sobj = OSMutexCreate(0, &err); /* uC/OS-II */ 34 | // ret = (int)(err == OS_NO_ERR); 35 | 36 | // *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */ 37 | // ret = (int)(*sobj != NULL); 38 | 39 | return ret; 40 | } 41 | 42 | 43 | 44 | /*------------------------------------------------------------------------*/ 45 | /* Delete a Synchronization Object */ 46 | /*------------------------------------------------------------------------*/ 47 | /* This function is called in f_mount() function to delete a synchronization 48 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 49 | / the f_mount() function fails with FR_INT_ERR. 50 | */ 51 | 52 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to any error */ 53 | _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 54 | ) 55 | { 56 | int ret; 57 | 58 | 59 | ret = CloseHandle(sobj); /* Win32 */ 60 | 61 | // ret = 1; /* uITRON (nothing to do) */ 62 | 63 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */ 64 | // ret = (int)(err == OS_NO_ERR); 65 | 66 | // vSemaphoreDelete(sobj); /* FreeRTOS */ 67 | // ret = 1; 68 | 69 | return ret; 70 | } 71 | 72 | 73 | 74 | /*------------------------------------------------------------------------*/ 75 | /* Request Grant to Access the Volume */ 76 | /*------------------------------------------------------------------------*/ 77 | /* This function is called on entering file functions to lock the volume. 78 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 79 | */ 80 | 81 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 82 | _SYNC_t sobj /* Sync object to wait */ 83 | ) 84 | { 85 | int ret; 86 | 87 | ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */ 88 | 89 | // ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */ 90 | 91 | // OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */ 92 | // ret = (int)(err == OS_NO_ERR); 93 | 94 | // ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */ 95 | 96 | return ret; 97 | } 98 | 99 | 100 | 101 | /*------------------------------------------------------------------------*/ 102 | /* Release Grant to Access the Volume */ 103 | /*------------------------------------------------------------------------*/ 104 | /* This function is called on leaving file functions to unlock the volume. 105 | */ 106 | 107 | void ff_rel_grant ( 108 | _SYNC_t sobj /* Sync object to be signaled */ 109 | ) 110 | { 111 | ReleaseMutex(sobj); /* Win32 */ 112 | 113 | // sig_sem(sobj); /* uITRON */ 114 | 115 | // OSMutexPost(sobj); /* uC/OS-II */ 116 | 117 | // xSemaphoreGive(sobj); /* FreeRTOS */ 118 | } 119 | 120 | #endif 121 | 122 | 123 | 124 | 125 | #if _USE_LFN == 3 /* LFN with a working buffer on the heap */ 126 | /*------------------------------------------------------------------------*/ 127 | /* Allocate a memory block */ 128 | /*------------------------------------------------------------------------*/ 129 | /* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. 130 | */ 131 | 132 | void* ff_memalloc ( /* Returns pointer to the allocated memory block */ 133 | UINT msize /* Number of bytes to allocate */ 134 | ) 135 | { 136 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 137 | } 138 | 139 | 140 | /*------------------------------------------------------------------------*/ 141 | /* Free a memory block */ 142 | /*------------------------------------------------------------------------*/ 143 | 144 | void ff_memfree ( 145 | void* mblock /* Pointer to the memory block to free */ 146 | ) 147 | { 148 | free(mblock); /* Discard the memory block with POSIX API */ 149 | } 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /source/fatfs/option/unicode.c: -------------------------------------------------------------------------------- 1 | #include "../ff.h" 2 | 3 | #if _USE_LFN != 0 4 | 5 | #if _CODE_PAGE == 932 /* Japanese Shift_JIS */ 6 | #include "cc932.c" 7 | #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ 8 | #include "cc936.c" 9 | #elif _CODE_PAGE == 949 /* Korean */ 10 | #include "cc949.c" 11 | #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ 12 | #include "cc950.c" 13 | #else /* Single Byte Character-Set */ 14 | #include "ccsbcs.c" 15 | #endif 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /source/fatfs/qff.c: -------------------------------------------------------------------------------- 1 | #include "qff.h" 2 | 3 | #define NUM_FS 4 4 | 5 | // don't use this area for anything else! 6 | static FATFS* fs = (FATFS*) 0x20316000; 7 | 8 | // currently open file systems 9 | static FRESULT fs_mounted[NUM_FS]; 10 | 11 | FRESULT f_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br) { 12 | FIL fp; 13 | FRESULT res; 14 | UINT brl; 15 | if (!br) br = &brl; 16 | 17 | res = f_open(&fp, path, FA_READ | FA_OPEN_EXISTING); 18 | if (res != FR_OK) return res; 19 | 20 | res = f_lseek(&fp, ofs); 21 | if (res != FR_OK) { 22 | f_close(&fp); 23 | return res; 24 | } 25 | 26 | res = f_read(&fp, buff, btr, br); 27 | f_close(&fp); 28 | 29 | return res; 30 | } 31 | 32 | FRESULT f_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw) { 33 | FIL fp; 34 | FRESULT res; 35 | UINT bwl; 36 | if (!bw) bw = &bwl; 37 | 38 | res = f_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS); 39 | if (res != FR_OK) return res; 40 | 41 | res = f_lseek(&fp, ofs); 42 | if (res != FR_OK) { 43 | f_close(&fp); 44 | return res; 45 | } 46 | 47 | res = f_write(&fp, buff, btw, bw); 48 | f_close(&fp); 49 | 50 | return res; 51 | } 52 | 53 | FATFS* fs_getobj (const TCHAR* path) { 54 | UINT fsnum = (path[1] == ':') ? *path - '0' : -1; 55 | return ((fsnum < NUM_FS) && (fs_mounted[fsnum] == FR_OK)) ? &fs[fsnum] : (FATFS*) 0; 56 | } 57 | 58 | FRESULT f_getfreebyte (const TCHAR* path, QWORD* bt) { 59 | DWORD free_clusters; 60 | FATFS* fsptr; 61 | FRESULT res; 62 | 63 | res = f_getfree(path, &free_clusters, &fsptr); 64 | if (res != FR_OK) return res; 65 | 66 | FATFS* fsobj = fs_getobj(path); 67 | if (!fsobj) return FR_NOT_READY; 68 | *bt = (QWORD) free_clusters * fsobj->csize * _MAX_SS; 69 | 70 | return res; 71 | } 72 | 73 | FRESULT f_gettotalbyte (const TCHAR* path, QWORD* bt) { 74 | FATFS* fsobj = fs_getobj(path); 75 | *bt = (fsobj) ? ((QWORD) (fsobj->n_fatent - 2) * fsobj->csize * _MAX_SS) : 0; 76 | return *bt ? FR_OK : FR_NOT_READY; 77 | } 78 | 79 | FRESULT fs_init(void) { 80 | for (UINT i = 0; i < NUM_FS; i++) { 81 | TCHAR* fsname = "X:"; 82 | *fsname = (TCHAR) ('0' + i); 83 | fs_mounted[i] = f_mount(fs + i, fsname, 1); 84 | if ((fs_mounted[i] != FR_OK) && (i == 0)) return fs_mounted[i]; // SD can't fail 85 | } 86 | return FR_OK; 87 | } 88 | 89 | FRESULT fs_deinit(void) { 90 | for (UINT i = 0; i < NUM_FS; i++) { 91 | TCHAR* fsname = "X:"; 92 | *fsname = (TCHAR) ('0' + i); 93 | if (fs_mounted[i] != FR_OK) continue; 94 | f_mount(0, fsname, 1); 95 | fs_mounted[i] = FR_NOT_READY; 96 | } 97 | return FR_OK; 98 | } 99 | -------------------------------------------------------------------------------- /source/fatfs/qff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ff.h" 4 | 5 | // additional quick read / write functions 6 | FRESULT f_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br); 7 | FRESULT f_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw); 8 | 9 | // find out drive free / total space 10 | FRESULT f_getfreebyte (const TCHAR* path, QWORD* bt); 11 | FRESULT f_gettotalbyte (const TCHAR* path, QWORD* bt); 12 | 13 | // stuff for initializing / deinitializing drives 14 | FRESULT fs_init(void); 15 | FRESULT fs_deinit(void); 16 | 17 | 18 | -------------------------------------------------------------------------------- /source/font/font.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------- 2 | #ifndef _font_h_ 3 | #define _font_h_ 4 | //--------------------------------------------------------------------------------- 5 | #if defined FONT_6X10 6 | #include "font_6x10.h" 7 | #elif defined FONT_ACORN 8 | #include "font_acorn_8x8.h" 9 | #elif defined FONT_GB 10 | #include "font_gb_7x6.h" 11 | #else 12 | #include "font_orig.h" // if nothing is selected 13 | #endif 14 | //--------------------------------------------------------------------------------- 15 | #endif //_font_h_ 16 | //--------------------------------------------------------------------------------- 17 | -------------------------------------------------------------------------------- /source/font/font_acorn_8x8.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------- 2 | // Linux Acorn 8x8 font 3 | // https://github.com/torvalds/linux/tree/master/lib/fonts 4 | //--------------------------------------------------------------------------------- 5 | #define FONT_WIDTH 8 6 | #define FONT_HEIGHT 8 7 | //--------------------------------------------------------------------------------- 8 | static const unsigned char font[] = { 9 | /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ 10 | /* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */ 11 | /* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */ 12 | /* 03 */ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^C */ 13 | /* 04 */ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^D */ 14 | /* 05 */ 0x00, 0x18, 0x3c, 0xe7, 0xe7, 0x3c, 0x18, 0x00, /* ^E */ 15 | /* 06 */ 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x7c, 0x10, 0x38, 16 | /* 07 */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 17 | /* 08 */ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 18 | /* 09 */ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 19 | /* 0A */ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 20 | /* 0B */ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, 21 | /* 0C */ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 22 | /* 0D */ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, 23 | /* 0E */ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 24 | /* 0F */ 0x18, 0xdb, 0x3c, 0xe7, 0xe7, 0x3c, 0xdb, 0x18, 25 | /* 10 */ 0x00, 0x60, 0x78, 0x7e, 0x7e, 0x78, 0x60, 0x00, /* |> */ 26 | /* 11 */ 0x00, 0x06, 0x1e, 0x7e, 0x7e, 0x1e, 0x06, 0x00, /* <| */ 27 | /* 12 */ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 28 | /* 13 */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 29 | /* 14 */ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 30 | /* 15 */ 0x3c, 0x60, 0x3c, 0x66, 0x3c, 0x06, 0x3c, 0x00, 31 | /* 16 */ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 32 | /* 17 */ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, 33 | /* 18 */ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 34 | /* 19 */ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 35 | /* 1A */ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 36 | /* 1B */ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 37 | /* 1C */ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 38 | /* 1D */ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 39 | /* 1E */ 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x00, /* /\ */ 40 | /* 1F */ 0x00, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, /* \/ */ 41 | /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ 42 | /* 21 */ 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, /* ! */ 43 | /* 22 */ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* " */ 44 | /* 23 */ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, /* # */ 45 | /* 24 */ 0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00, /* $ */ 46 | /* 25 */ 0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00, /* % */ 47 | /* 26 */ 0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00, /* & */ 48 | /* 27 */ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' */ 49 | /* 28 */ 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, /* ( */ 50 | /* 29 */ 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, /* ) */ 51 | /* 2A */ 0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00, /* * */ 52 | /* 2B */ 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, /* + */ 53 | /* 2C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, /* , */ 54 | /* 2D */ 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, /* - */ 55 | /* 2E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, /* . */ 56 | /* 2F */ 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, /* / */ 57 | /* 30 */ 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00, /* 0 */ 58 | /* 31 */ 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* 1 */ 59 | /* 32 */ 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* 2 */ 60 | /* 33 */ 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, /* 3 */ 61 | /* 34 */ 0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00, /* 4 */ 62 | /* 35 */ 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, /* 5 */ 63 | /* 36 */ 0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, /* 6 */ 64 | /* 37 */ 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, /* 7 */ 65 | /* 38 */ 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, /* 8 */ 66 | /* 39 */ 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, /* 9 */ 67 | /* 3A */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */ 68 | /* 3B */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */ 69 | /* 3C */ 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */ 70 | /* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */ 71 | /* 3E */ 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */ 72 | /* 3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */ 73 | /* 40 */ 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */ 74 | /* 41 */ 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* A */ 75 | /* 42 */ 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, /* B */ 76 | /* 43 */ 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, /* C */ 77 | /* 44 */ 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, /* D */ 78 | /* 45 */ 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, /* E */ 79 | /* 46 */ 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, /* F */ 80 | /* 47 */ 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, /* G */ 81 | /* 48 */ 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, /* H */ 82 | /* 49 */ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, /* I */ 83 | /* 4A */ 0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, /* J */ 84 | /* 4B */ 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, /* K */ 85 | /* 4C */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, /* L */ 86 | /* 4D */ 0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00, /* M */ 87 | /* 4E */ 0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00, /* N */ 88 | /* 4F */ 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* O */ 89 | /* 50 */ 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, /* P */ 90 | /* 51 */ 0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00, /* Q */ 91 | /* 52 */ 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, /* R */ 92 | /* 53 */ 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, /* S */ 93 | /* 54 */ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* T */ 94 | /* 55 */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, /* U */ 95 | /* 56 */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* V */ 96 | /* 57 */ 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00, /* W */ 97 | /* 58 */ 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, /* X */ 98 | /* 59 */ 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, /* Y */ 99 | /* 5A */ 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, /* Z */ 100 | /* 5B */ 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00, /* [ */ 101 | /* 5C */ 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, /* \ */ 102 | /* 5D */ 0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, /* ] */ 103 | /* 5E */ 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^ */ 104 | /* 5F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, /* _ */ 105 | /* 60 */ 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ` */ 106 | /* 61 */ 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, /* a */ 107 | /* 62 */ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, /* b */ 108 | /* 63 */ 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, /* c */ 109 | /* 64 */ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, /* d */ 110 | /* 65 */ 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, /* e */ 111 | /* 66 */ 0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00, /* f */ 112 | /* 67 */ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* g */ 113 | /* 68 */ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* h */ 114 | /* 69 */ 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, /* i */ 115 | /* 6A */ 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70, /* j */ 116 | /* 6B */ 0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, /* k */ 117 | /* 6C */ 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, /* l */ 118 | /* 6D */ 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00, /* m */ 119 | /* 6E */ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, /* n */ 120 | /* 6F */ 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, /* o */ 121 | /* 70 */ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, /* p */ 122 | /* 71 */ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07, /* q */ 123 | /* 72 */ 0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00, /* r */ 124 | /* 73 */ 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, /* s */ 125 | /* 74 */ 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00, /* t */ 126 | /* 75 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, /* u */ 127 | /* 76 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, /* v */ 128 | /* 77 */ 0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, /* w */ 129 | /* 78 */ 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, /* x */ 130 | /* 79 */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C, /* y */ 131 | /* 7A */ 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, /* z */ 132 | /* 7B */ 0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00, /* { */ 133 | /* 7C */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* | */ 134 | /* 7D */ 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, /* } */ 135 | /* 7E */ 0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */ 136 | /* 7F */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*  */ 137 | /* 80 */ 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x30, 0x60, 138 | /* 81 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00, 139 | /* 82 */ 0x0c, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 140 | /* 83 */ 0x18, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, 141 | /* 84 */ 0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, 142 | /* 85 */ 0x30, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, 143 | /* 86 */ 0x3c, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, 144 | /* 87 */ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x60, 145 | /* 88 */ 0x3c, 0x66, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 146 | /* 89 */ 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 147 | /* 8A */ 0x30, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 148 | /* 8B */ 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, 149 | /* 8C */ 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, 150 | /* 8D */ 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, 151 | /* 8E */ 0x66, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, 152 | /* 8F */ 0x18, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, 153 | /* 90 */ 0x0c, 0x18, 0x7e, 0x60, 0x7c, 0x60, 0x7e, 0x00, 154 | /* 91 */ 0x00, 0x00, 0x3f, 0x0d, 0x3f, 0x6c, 0x3f, 0x00, 155 | /* 92 */ 0x3f, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x67, 0x00, 156 | /* 93 */ 0x3c, 0x66, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, 157 | /* 94 */ 0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, 158 | /* 95 */ 0x30, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, 159 | /* 96 */ 0x3c, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, 160 | /* 97 */ 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, 161 | /* 98 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 162 | /* 99 */ 0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 163 | /* 9A */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 164 | /* 9B */ 0x08, 0x3e, 0x6b, 0x68, 0x6b, 0x3e, 0x08, 0x00, 165 | /* 9C */ 0x1c, 0x36, 0x30, 0x7c, 0x30, 0x30, 0x7e, 0x00, 166 | /* 9D */ 0x66, 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 167 | /* 9E */ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 168 | /* 9F */ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0xd8, 0x70, 0x00, 169 | /* A0 */ 0x0c, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, 170 | /* A1 */ 0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, 171 | /* A2 */ 0x0c, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, 172 | /* A3 */ 0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, 173 | /* A4 */ 0x36, 0x6c, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x00, 174 | /* A5 */ 0x36, 0x6c, 0x00, 0x66, 0x76, 0x6e, 0x66, 0x00, 175 | /* A6 */ 0x1c, 0x06, 0x1e, 0x36, 0x1e, 0x00, 0x3e, 0x00, 176 | /* A7 */ 0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, 177 | /* A8 */ 0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3c, 0x00, 178 | /* A9 */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 179 | /* AA */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 180 | /* AB */ 0x40, 0xc0, 0x40, 0x4f, 0x41, 0x0f, 0x08, 0x0f, 181 | /* AC */ 0x40, 0xc0, 0x40, 0x48, 0x48, 0x0a, 0x0f, 0x02, 182 | /* AD */ 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 183 | /* AE */ 0x00, 0x33, 0x66, 0xcc, 0xcc, 0x66, 0x33, 0x00, 184 | /* AF */ 0x00, 0xcc, 0x66, 0x33, 0x33, 0x66, 0xcc, 0x00, 185 | /* B0 */ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 186 | /* B1 */ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 187 | /* B2 */ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 188 | /* B3 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 189 | /* B4 */ 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 190 | /* B5 */ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 191 | /* B6 */ 0x66, 0x66, 0x66, 0xe6, 0x66, 0x66, 0x66, 0x66, 192 | /* B7 */ 0x00, 0x00, 0x00, 0xfe, 0x66, 0x66, 0x66, 0x66, 193 | /* B8 */ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 194 | /* B9 */ 0x66, 0x66, 0xe6, 0x06, 0xe6, 0x66, 0x66, 0x66, 195 | /* BA */ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 196 | /* BB */ 0x00, 0x00, 0xfe, 0x06, 0xe6, 0x66, 0x66, 0x66, 197 | /* BC */ 0x66, 0x66, 0xe6, 0x06, 0xfe, 0x00, 0x00, 0x00, 198 | /* BD */ 0x66, 0x66, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 199 | /* BE */ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 200 | /* BF */ 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 201 | /* C0 */ 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 202 | /* C1 */ 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 203 | /* C2 */ 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 204 | /* C3 */ 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 205 | /* C4 */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 206 | /* C5 */ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 207 | /* C6 */ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 208 | /* C7 */ 0x66, 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 209 | /* C8 */ 0x66, 0x66, 0x67, 0x60, 0x7f, 0x00, 0x00, 0x00, 210 | /* C9 */ 0x00, 0x00, 0x7f, 0x60, 0x67, 0x66, 0x66, 0x66, 211 | /* CA */ 0x66, 0x66, 0xe7, 0x00, 0xff, 0x00, 0x00, 0x00, 212 | /* CB */ 0x00, 0x00, 0xff, 0x00, 0xe7, 0x66, 0x66, 0x66, 213 | /* CC */ 0x66, 0x66, 0x67, 0x60, 0x67, 0x66, 0x66, 0x66, 214 | /* CD */ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 215 | /* CE */ 0x66, 0x66, 0xe7, 0x00, 0xe7, 0x66, 0x66, 0x66, 216 | /* CF */ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 217 | /* D0 */ 0x66, 0x66, 0x66, 0xff, 0x00, 0x00, 0x00, 0x00, 218 | /* D1 */ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 219 | /* D2 */ 0x00, 0x00, 0x00, 0xff, 0x66, 0x66, 0x66, 0x66, 220 | /* D3 */ 0x66, 0x66, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00, 221 | /* D4 */ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 222 | /* D5 */ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 223 | /* D6 */ 0x00, 0x00, 0x00, 0x7f, 0x66, 0x66, 0x66, 0x66, 224 | /* D7 */ 0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0x66, 225 | /* D8 */ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 226 | /* D9 */ 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 227 | /* DA */ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 228 | /* DB */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 229 | /* DC */ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 230 | /* DD */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 231 | /* DE */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 232 | /* DF */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 233 | /* E0 */ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 234 | /* E1 */ 0x3c, 0x66, 0x66, 0x6c, 0x66, 0x66, 0x6c, 0xc0, 235 | /* E2 */ 0xfe, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 236 | /* E3 */ 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 237 | /* E4 */ 0xfe, 0xc6, 0x60, 0x30, 0x60, 0xc6, 0xfe, 0x00, 238 | /* E5 */ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 239 | /* E6 */ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x60, 240 | /* E7 */ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, 241 | /* E8 */ 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x7e, 242 | /* E9 */ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, 243 | /* EA */ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 244 | /* EB */ 0x0e, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x3c, 0x00, 245 | /* EC */ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 246 | /* ED */ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, 247 | /* EE */ 0x1e, 0x30, 0x60, 0x7e, 0x60, 0x30, 0x1e, 0x00, 248 | /* EF */ 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 249 | /* F0 */ 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 250 | /* F1 */ 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 251 | /* F2 */ 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 252 | /* F3 */ 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 253 | /* F4 */ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 254 | /* F5 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 255 | /* F6 */ 0x00, 0x18, 0x00, 0xff, 0x00, 0x18, 0x00, 0x00, 256 | /* F7 */ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 257 | /* F8 */ 0x3c, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 258 | /* F9 */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 259 | /* FA */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 260 | /* FB */ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 261 | /* FC */ 0x6c, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 262 | /* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00, 263 | /* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 264 | /* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 265 | }; 266 | const int font_size = sizeof(font); 267 | -------------------------------------------------------------------------------- /source/font/font_gb_7x6.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file was autogenerated by raw2c. 3 | Visit http://www.devkitpro.org 4 | */ 5 | //--------------------------------------------------------------------------------- 6 | // GB Font by Ennea 7 | //--------------------------------------------------------------------------------- 8 | #define FONT_WIDTH 7 9 | #define FONT_HEIGHT 6 10 | //--------------------------------------------------------------------------------- 11 | static const unsigned char font[] = { 12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21 | 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0x10, 0x18, 0xfc, 0xfc, 22 | 0x18, 0x10, 0x20, 0x60, 0xfc, 0xfc, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0xd8, 0xd8, 0x90, 0x00, 25 | 0x00, 0x00, 0x28, 0x7c, 0x28, 0x50, 0xf8, 0x50, 0x30, 0x78, 0x70, 0x38, 0x78, 0x30, 0x44, 0xe8, 26 | 0x50, 0x28, 0x5c, 0x88, 0x60, 0x90, 0x40, 0xa8, 0x90, 0x6c, 0x30, 0x30, 0x20, 0x00, 0x00, 0x00, 27 | 0x30, 0x60, 0x60, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00, 0x30, 0x78, 0x30, 28 | 0x48, 0x00, 0x30, 0x30, 0xfc, 0xfc, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x20, 0x00, 0x00, 29 | 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x08, 0x18, 0x30, 0x30, 0x60, 0x40, 30 | 0x78, 0xcc, 0xdc, 0xec, 0xcc, 0x78, 0x30, 0x70, 0x30, 0x30, 0x30, 0x78, 0x78, 0x9c, 0x1c, 0x78, 31 | 0xe0, 0xfc, 0xf8, 0x1c, 0x78, 0x1c, 0x1c, 0xf8, 0x78, 0xd8, 0x98, 0x98, 0xfc, 0x18, 0xf8, 0xc0, 32 | 0xf8, 0x1c, 0x9c, 0x78, 0x78, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0xfc, 0x0c, 0x18, 0x30, 0x70, 0x70, 33 | 0x78, 0x9c, 0x78, 0x9c, 0x9c, 0x78, 0x78, 0x9c, 0x9c, 0x7c, 0x1c, 0x78, 0x00, 0x30, 0x30, 0x00, 34 | 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x30, 0x20, 0x0c, 0x38, 0xe0, 0xe0, 0x38, 0x0c, 0x00, 0xfc, 35 | 0xfc, 0x00, 0xfc, 0xfc, 0xc0, 0x70, 0x1c, 0x1c, 0x70, 0xc0, 0x78, 0x9c, 0x1c, 0x38, 0x00, 0x30, 36 | 0x38, 0x44, 0xbc, 0xa4, 0xdc, 0x60, 0x78, 0x9c, 0x9c, 0xfc, 0x9c, 0x9c, 0xf8, 0xcc, 0xf8, 0xcc, 37 | 0xcc, 0xf8, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0xf8, 0x9c, 0x9c, 0x9c, 0x9c, 0xf8, 0xfc, 0xc0, 38 | 0xf8, 0xc0, 0xc0, 0xfc, 0xfc, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0x78, 0xcc, 0xc0, 0xdc, 0xcc, 0x7c, 39 | 0x8c, 0x8c, 0xfc, 0x8c, 0x8c, 0x8c, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x3c, 0x18, 0x18, 0xd8, 40 | 0xd8, 0x70, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0x8c, 0xdc, 41 | 0xfc, 0xac, 0x8c, 0x8c, 0x8c, 0xcc, 0xec, 0xbc, 0x9c, 0x8c, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 42 | 0xf8, 0xcc, 0xcc, 0xf8, 0xc0, 0xc0, 0x78, 0xc4, 0xc4, 0xd4, 0xc8, 0x74, 0xf8, 0xcc, 0xcc, 0xf8, 43 | 0xd0, 0xcc, 0x78, 0xc0, 0x78, 0x1c, 0x9c, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x8c, 0x8c, 44 | 0x8c, 0x8c, 0x9c, 0x78, 0x8c, 0x8c, 0x8c, 0x8c, 0x58, 0x30, 0x8c, 0x8c, 0xac, 0xfc, 0xdc, 0x8c, 45 | 0x8c, 0x58, 0x30, 0x70, 0xc8, 0x84, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0xfc, 0x1c, 0x38, 0x70, 46 | 0xe0, 0xfc, 0x70, 0x60, 0x60, 0x60, 0x60, 0x70, 0x40, 0x60, 0x30, 0x30, 0x18, 0x08, 0x38, 0x18, 47 | 0x18, 0x18, 0x18, 0x38, 0x30, 0x78, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 48 | 0x30, 0x30, 0x10, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x9c, 0xfc, 0x9c, 0x9c, 0xf8, 0xcc, 0xf8, 0xcc, 49 | 0xcc, 0xf8, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0xf8, 0x9c, 0x9c, 0x9c, 0x9c, 0xf8, 0xfc, 0xc0, 50 | 0xf8, 0xc0, 0xc0, 0xfc, 0xfc, 0xc0, 0xc0, 0xf8, 0xc0, 0xc0, 0x78, 0xcc, 0xc0, 0xdc, 0xcc, 0x7c, 51 | 0x8c, 0x8c, 0xfc, 0x8c, 0x8c, 0x8c, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x3c, 0x18, 0x18, 0xd8, 52 | 0xd8, 0x70, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0x8c, 0xdc, 53 | 0xfc, 0xac, 0x8c, 0x8c, 0x8c, 0xcc, 0xec, 0xbc, 0x9c, 0x8c, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 54 | 0xf8, 0xcc, 0xcc, 0xf8, 0xc0, 0xc0, 0x78, 0xc4, 0xc4, 0xd4, 0xc8, 0x74, 0xf8, 0xcc, 0xcc, 0xf8, 55 | 0xd0, 0xcc, 0x78, 0xc0, 0x78, 0x1c, 0x9c, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x8c, 0x8c, 56 | 0x8c, 0x8c, 0x9c, 0x78, 0x8c, 0x8c, 0x8c, 0x8c, 0x58, 0x30, 0x8c, 0x8c, 0xac, 0xfc, 0xdc, 0x8c, 57 | 0x8c, 0x58, 0x30, 0x70, 0xc8, 0x84, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0xfc, 0x1c, 0x38, 0x70, 58 | 0xe0, 0xfc, 0x30, 0x60, 0xc0, 0x60, 0x60, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 59 | 0x0c, 0x18, 0x18, 0x30, 0x00, 0x64, 0xfc, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 108 | 109 | }; 110 | const int font_size = sizeof(font); 111 | -------------------------------------------------------------------------------- /source/font/font_orig.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file was autogenerated by raw2c. 3 | Visit http://www.devkitpro.org 4 | */ 5 | //--------------------------------------------------------------------------------- 6 | // Original Decrypt9 font 7 | //--------------------------------------------------------------------------------- 8 | #define FONT_WIDTH 8 9 | #define FONT_HEIGHT 8 10 | //--------------------------------------------------------------------------------- 11 | static const unsigned char font[] = { 12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, 13 | 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 14 | 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, 15 | 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 16 | 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 17 | 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, 18 | 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00, 19 | 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, 20 | 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, 21 | 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 22 | 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, 23 | 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, 24 | 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00, 25 | 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 26 | 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, 27 | 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, 29 | 0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 30 | 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00, 31 | 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 33 | 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 36 | 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00, 37 | 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, 38 | 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 39 | 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, 40 | 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, 41 | 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 42 | 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 43 | 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, 44 | 0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 45 | 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 46 | 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, 47 | 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, 48 | 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 49 | 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 50 | 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, 51 | 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 52 | 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, 53 | 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, 54 | 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 55 | 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, 56 | 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, 57 | 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 58 | 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 59 | 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 60 | 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 61 | 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, 62 | 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 63 | 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78, 64 | 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 65 | 0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, 66 | 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, 67 | 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 68 | 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, 69 | 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00, 70 | 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 71 | 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 72 | 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 73 | 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, 74 | 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, 75 | 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 76 | 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 77 | 0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 78 | 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 79 | 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, 80 | 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 81 | 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 82 | 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 83 | 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 84 | 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00, 85 | 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 86 | 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 87 | 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 88 | 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 89 | 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, 90 | 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00, 91 | 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, 92 | 0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 93 | 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 94 | 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, 95 | 0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 96 | 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, 98 | 0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, 99 | 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 100 | 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 101 | 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 102 | 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 103 | 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 104 | 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 105 | 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 106 | 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 107 | 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 108 | 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 109 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 110 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 111 | 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 112 | 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 113 | 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 114 | 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 115 | 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 116 | 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 117 | 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 118 | 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 119 | 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 120 | 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 121 | 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 122 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 123 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 124 | 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, 125 | 0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, 126 | 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00, 127 | 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, 128 | 0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, 129 | 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, 130 | 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, 131 | 0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 132 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 133 | 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, 134 | 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 135 | 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 136 | 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 137 | 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, 138 | 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00, 139 | 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 140 | 141 | }; 142 | const int font_size = sizeof(font); 143 | -------------------------------------------------------------------------------- /source/installer.c: -------------------------------------------------------------------------------- 1 | #include "installer.h" 2 | #include "safewrite.h" 3 | #include "validator.h" 4 | #include "unittype.h" 5 | #include "nand.h" 6 | #include "sdmmc.h" 7 | #include "ui.h" 8 | #include "qff.h" 9 | #include "hid.h" 10 | 11 | #define COLOR_STATUS(s) ((s == STATUS_GREEN) ? COLOR_BRIGHTGREEN : (s == STATUS_YELLOW) ? COLOR_BRIGHTYELLOW : (s == STATUS_RED) ? COLOR_RED : COLOR_DARKGREY) 12 | 13 | #define MIN_SD_FREE (16 * 1024 * 1024) // 16MB 14 | 15 | #define NAME_SIGHAXFIRM (IS_DEVKIT ? INPUT_PATH "/" NAME_FIRM "_dev.firm" : INPUT_PATH "/" NAME_FIRM ".firm") 16 | #define NAME_SIGHAXFIRMSHA (IS_DEVKIT ? INPUT_PATH "/" NAME_FIRM "_dev.firm.sha" : INPUT_PATH "/" NAME_FIRM ".firm.sha") 17 | #define NAME_SECTOR0x96 (IS_DEVKIT ? INPUT_PATH "/secret_sector_dev.bin" : INPUT_PATH "/secret_sector.bin") 18 | #define NAME_FIRMBACKUP INPUT_PATH "/firm%lu_enc.bak" 19 | #define NAME_SECTORBACKUP INPUT_PATH "/sector0x96_enc.bak" 20 | 21 | #define MAX_STAGE2_SIZE 0x89A00 22 | 23 | #define STATUS_GREY -1 24 | #define STATUS_GREEN 0 25 | #define STATUS_YELLOW 1 26 | #define STATUS_RED 2 27 | 28 | static int statusA9lh = STATUS_GREY; 29 | static int statusSdCard = STATUS_GREY; 30 | static int statusFirm = STATUS_GREY; 31 | static int statusSector = STATUS_GREY; 32 | static int statusCrypto = STATUS_GREY; 33 | static int statusBackup = STATUS_GREY; 34 | static int statusInstall = STATUS_GREY; 35 | static char msgA9lh[64] = "not started"; 36 | static char msgSdCard[64] = "not started"; 37 | static char msgFirm[64] = "not started"; 38 | static char msgSector[64] = "not started"; 39 | static char msgCrypto[64] = "not started"; 40 | static char msgBackup[64] = "not started"; 41 | static char msgInstall[64] = "not started"; 42 | 43 | u32 ShowInstallerStatus(void) { 44 | const u32 pos_xb = 10; 45 | const u32 pos_x0 = pos_xb + 4; 46 | const u32 pos_x1 = pos_x0 + (17*FONT_WIDTH_EXT); 47 | const u32 pos_yb = 10; 48 | const u32 pos_yu = 230; 49 | const u32 pos_y0 = pos_yb + 50; 50 | const u32 stp = 14; 51 | 52 | // DrawStringF(BOT_SCREEN, pos_xb, pos_yb, COLOR_STD_FONT, COLOR_STD_BG, "SafeB9SInstaller v" VERSION "\n" "-----------------------" "\n" "https://github.com/d0k3/SafeB9SInstaller"); 53 | DrawStringF(BOT_SCREEN, pos_xb, pos_yb, COLOR_STD_FONT, COLOR_STD_BG, APP_TITLE "\n" "%.*s" "\n" APP_URL, 54 | strnlen(APP_TITLE, 32), "--------------------------------"); 55 | 56 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (0*stp), COLOR_STD_FONT, COLOR_STD_BG, "ARM9LoaderHax -"); 57 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (1*stp), COLOR_STD_FONT, COLOR_STD_BG, "MicroSD Card -"); 58 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (2*stp), COLOR_STD_FONT, COLOR_STD_BG, "Sighaxed FIRM -"); 59 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (3*stp), COLOR_STD_FONT, COLOR_STD_BG, "Secret Sector -"); 60 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (4*stp), COLOR_STD_FONT, COLOR_STD_BG, "Crypto Status -"); 61 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (5*stp), COLOR_STD_FONT, COLOR_STD_BG, "Backup Status -"); 62 | DrawStringF(BOT_SCREEN, pos_x0, pos_y0 + (6*stp), COLOR_STD_FONT, COLOR_STD_BG, "Install Status -"); 63 | 64 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (0*stp), COLOR_STATUS(statusA9lh) , COLOR_STD_BG, "%-21.21s", msgA9lh ); 65 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (1*stp), COLOR_STATUS(statusSdCard) , COLOR_STD_BG, "%-21.21s", msgSdCard ); 66 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (2*stp), COLOR_STATUS(statusFirm) , COLOR_STD_BG, "%-21.21s", msgFirm ); 67 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (3*stp), COLOR_STATUS(statusSector) , COLOR_STD_BG, "%-21.21s", msgSector ); 68 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (4*stp), COLOR_STATUS(statusCrypto) , COLOR_STD_BG, "%-21.21s", msgCrypto ); 69 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (5*stp), COLOR_STATUS(statusBackup) , COLOR_STD_BG, "%-21.21s", msgBackup ); 70 | DrawStringF(BOT_SCREEN, pos_x1, pos_y0 + (6*stp), COLOR_STATUS(statusInstall), COLOR_STD_BG, "%-21.21s", msgInstall); 71 | 72 | DrawStringF(BOT_SCREEN, pos_xb, pos_yu - 10, COLOR_STD_FONT, COLOR_STD_BG, APP_USAGE); 73 | return 0; 74 | } 75 | 76 | u32 SafeB9SInstaller(void) { 77 | UINT bt; 78 | u32 ret = 0; 79 | 80 | // initialization 81 | ShowString("Initializing, please wait..."); 82 | 83 | 84 | // step #0 - a9lh check 85 | snprintf(msgA9lh, 64, (IS_A9LH && !IS_SIGHAX) ? "installed" : "not installed"); 86 | statusA9lh = STATUS_GREEN; 87 | ShowInstallerStatus(); 88 | 89 | // step #1 - init/check SD card 90 | snprintf(msgSdCard, 64, "checking..."); 91 | statusSdCard = STATUS_YELLOW; 92 | ShowInstallerStatus(); 93 | u64 sdFree = 0; 94 | u64 sdTotal = 0; 95 | if ((fs_init() != FR_OK) || 96 | (f_getfreebyte("0:", &sdFree) != FR_OK) || 97 | (f_gettotalbyte("0:", &sdTotal) != FR_OK)) { 98 | snprintf(msgSdCard, 64, "init failed"); 99 | statusSdCard = STATUS_RED; 100 | return 1; 101 | } 102 | InitNandCrypto(); // for sector0x96 crypto and NAND drives 103 | snprintf(msgSdCard, 64, "%lluMB/%lluMB free", sdFree / (1024 * 1024), sdTotal / (1024 * 1024)); 104 | statusSdCard = (sdFree < MIN_SD_FREE) ? STATUS_RED : STATUS_GREEN; 105 | ShowInstallerStatus(); 106 | if (sdFree < MIN_SD_FREE) return 1; 107 | // SD card okay! 108 | 109 | 110 | // step #2 - check sighaxed firm 111 | snprintf(msgFirm, 64, "checking..."); 112 | statusFirm = STATUS_YELLOW; 113 | ShowInstallerStatus(); 114 | u8 firm_sha[0x20]; 115 | UINT firm_size; 116 | bool unknown_payload = false; 117 | if ((f_qread(NAME_SIGHAXFIRM, FIRM_BUFFER, 0, FIRM_BUFFER_SIZE, &firm_size) != FR_OK) || 118 | (firm_size < 0x200)) { 119 | snprintf(msgFirm, 64, "file not found"); 120 | statusFirm = STATUS_RED; 121 | return 1; 122 | } 123 | if ((f_qread(NAME_SIGHAXFIRMSHA, firm_sha, 0, 0x20, &bt) != FR_OK) || (bt != 0x20)) { 124 | snprintf(msgFirm, 64, ".sha file not found"); 125 | statusFirm = STATUS_RED; 126 | return 1; 127 | } 128 | if (ValidateFirm(FIRM_BUFFER, firm_sha, firm_size, NULL) != 0) { 129 | snprintf(msgFirm, 64, "invalid FIRM"); 130 | statusFirm = STATUS_RED; 131 | return 1; 132 | } 133 | if (CheckFirmSigHax(FIRM_BUFFER) != 0) { 134 | snprintf(msgFirm, 64, "not sighaxed"); 135 | statusFirm = STATUS_RED; 136 | return 1; 137 | } 138 | if (CheckFirmPayload(FIRM_BUFFER, msgFirm) != 0) { 139 | #ifndef OPEN_INSTALLER 140 | statusFirm = STATUS_RED; 141 | return 1; 142 | #else 143 | unknown_payload = true; 144 | #endif 145 | } 146 | statusFirm = unknown_payload ? STATUS_YELLOW : STATUS_GREEN; 147 | ShowInstallerStatus(); 148 | // provided FIRM is okay! 149 | 150 | 151 | // step #3 - check secret_sector.bin file 152 | u8 secret_sector[0x200] = { 0 }; 153 | if (IS_A9LH && !IS_SIGHAX && !IS_O3DS) { 154 | snprintf(msgSector, 64, "checking..."); 155 | statusSector = STATUS_YELLOW; 156 | ShowInstallerStatus(); 157 | if ((f_qread(NAME_SECTOR0x96, secret_sector, 0, 0x200, &bt) != FR_OK) || (bt != 0x200)) { 158 | snprintf(msgSector, 64, "file not found"); 159 | statusSector = STATUS_RED; 160 | return 1; 161 | } 162 | if (ValidateSector(secret_sector) != 0) { 163 | snprintf(msgSector, 64, "invalid file"); 164 | statusSector = STATUS_RED; 165 | return 1; 166 | } 167 | snprintf(msgSector, 64, "loaded & verified"); 168 | } else snprintf(msgSector, 64, "not required"); 169 | statusSector = STATUS_GREEN; 170 | ShowInstallerStatus(); 171 | // secret_sector.bin okay or not required! 172 | 173 | 174 | // step #4 - check NAND crypto 175 | snprintf(msgCrypto, 64, "checking..."); 176 | statusCrypto = STATUS_YELLOW; 177 | ShowInstallerStatus(); 178 | u32 n_firms = 0; 179 | for (; n_firms < 8; n_firms++) { 180 | NandPartitionInfo np_info; 181 | if (GetNandPartitionInfo(&np_info, NP_TYPE_FIRM, NP_SUBTYPE_CTR, n_firms) != 0) break; 182 | if ((firm_size > np_info.count * 0x200) || (np_info.count * 0x200 > WORK_BUFFER_SIZE)) { 183 | n_firms = 0; 184 | break; 185 | } 186 | } 187 | if (!n_firms) { 188 | snprintf(msgCrypto, 64, "FIRM partition fail"); 189 | statusCrypto = STATUS_RED; 190 | return 1; 191 | } 192 | if (!CheckFirmCrypto()) { 193 | snprintf(msgCrypto, 64, "FIRM crypto fail"); 194 | statusCrypto = STATUS_RED; 195 | return 1; 196 | } 197 | if ((IS_A9LH && !IS_SIGHAX && !IS_O3DS) && !CheckSector0x96Crypto()) { 198 | snprintf(msgCrypto, 64, "OTP crypto fail"); 199 | statusCrypto = STATUS_RED; 200 | return 1; 201 | } 202 | snprintf(msgCrypto, 64, "all checks passed"); 203 | statusCrypto = STATUS_GREEN; 204 | ShowInstallerStatus(); 205 | 206 | 207 | // step #X - point of no return 208 | if (!ShowUnlockSequence(unknown_payload ? 6 : 1, unknown_payload ? 209 | "!!! FIRM NOT RECOGNIZED !!!\nProceeding may lead to a BRICK!\n \nTo proceed, enter the sequence\nbelow or press B to cancel." : 210 | "All input files verified.\n \nTo install FIRM, enter the sequence\nbelow or press B to cancel.")) { 211 | snprintf(msgBackup, 64, "cancelled by user"); 212 | snprintf(msgInstall, 64, "cancelled by user"); 213 | statusBackup = STATUS_YELLOW; 214 | statusInstall = STATUS_YELLOW; 215 | return 1; 216 | } 217 | 218 | 219 | // step #5 - backup of current FIRMs and sector 0x96 220 | snprintf(msgBackup, 64, "FIRM backup..."); 221 | statusBackup = STATUS_YELLOW; 222 | ShowInstallerStatus(); 223 | ShowProgress(0, 0, "FIRM backup"); 224 | for (u32 i = 0; i < n_firms; i++) { 225 | NandPartitionInfo np_info; 226 | ret = GetNandPartitionInfo(&np_info, NP_TYPE_FIRM, NP_SUBTYPE_CTR, i); 227 | if (ret != 0) break; 228 | u32 fsize = np_info.count * 0x200; 229 | u32 foffset = np_info.sector * 0x200; 230 | char bakname[64]; 231 | snprintf(bakname, 64, NAME_FIRMBACKUP, i); 232 | snprintf(msgBackup, 64, "FIRM backup (%lu/%lu)", i, n_firms); 233 | ShowInstallerStatus(); 234 | if ((ReadNandBytes(WORK_BUFFER, foffset, fsize, 0xFF) != 0) || 235 | (SafeQWriteFile(bakname, WORK_BUFFER, fsize) != 0)) { 236 | ret = 1; 237 | break; 238 | } 239 | ShowProgress(i + 1, n_firms, "FIRM backup"); 240 | } 241 | if (ret != 0) { 242 | snprintf(msgBackup, 64, "FIRM backup fail"); 243 | statusBackup = STATUS_RED; 244 | return 1; 245 | } 246 | if ((IS_A9LH && !IS_SIGHAX)) { 247 | snprintf(msgBackup, 64, "0x96 backup..."); 248 | ShowInstallerStatus(); 249 | u8 sector_backup0[0x200]; 250 | u8 sector_backup1[0x200]; 251 | f_unlink(NAME_SECTORBACKUP); 252 | if ((ReadNandSectors(sector_backup0, 0x96, 1, 0xFF) != 0) || 253 | (f_qwrite(NAME_SECTORBACKUP, sector_backup0, 0, 0x200, &bt) != FR_OK) || (bt != 0x200) || 254 | (f_qread(NAME_SECTORBACKUP, sector_backup1, 0, 0x200, &bt) != FR_OK) || (bt != 0x200) || 255 | (memcmp(sector_backup0, sector_backup1, 0x200) != 0)) { 256 | snprintf(msgBackup, 64, "0x96 backup fail"); 257 | statusBackup = STATUS_RED; 258 | return 1; 259 | } 260 | } 261 | snprintf(msgBackup, 64, "backed up & verified"); 262 | statusBackup = STATUS_GREEN; 263 | ShowInstallerStatus(); 264 | // backups done 265 | 266 | 267 | // step #6 - install sighaxed FIRM 268 | snprintf(msgInstall, 64, "FIRM install..."); 269 | statusInstall = STATUS_YELLOW; 270 | ShowInstallerStatus(); 271 | #ifndef NO_WRITE 272 | ShowProgress(0, 0, "FIRM install"); 273 | do { 274 | for (u32 i = 0; i < n_firms; i++) { 275 | NandPartitionInfo np_info; 276 | ret = GetNandPartitionInfo(&np_info, NP_TYPE_FIRM, NP_SUBTYPE_CTR, i); 277 | if (ret != 0) break; 278 | ret = SafeWriteNand(FIRM_BUFFER, np_info.sector * 0x200, firm_size, np_info.keyslot); 279 | if (ret != 0) break; 280 | ShowProgress(i+1, n_firms, "FIRM install"); 281 | snprintf(msgInstall, 64, "FIRM install (%li/8)", i+1); 282 | ShowInstallerStatus(); 283 | } 284 | if (ret != 0) break; 285 | uint8_t emptyStage2[MAX_STAGE2_SIZE]={0}; 286 | // Uninstall a9lh stage 2 always if firm flashed ok 287 | // This prevents false positives in the event of cfw uninstall 288 | ret = sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, emptyStage2); 289 | if (ret != 0) break; 290 | if ((IS_A9LH && !IS_SIGHAX)) { 291 | snprintf(msgInstall, 64, "0x96 revert..."); 292 | ShowInstallerStatus(); 293 | ret = SafeWriteNand(secret_sector, SECTOR_SECRET * 0x200, 0x200, IS_O3DS ? 0xFF : 0x11); 294 | if (ret == 0) snprintf(msgA9lh, 64, "uninstalled"); 295 | } 296 | } while (false); 297 | if (ret == 0) { 298 | snprintf(msgInstall, 64, "install success!"); 299 | statusInstall = STATUS_GREEN; 300 | return 0; 301 | } else { 302 | snprintf(msgInstall, 64, "install failed"); 303 | statusInstall = STATUS_RED; 304 | if ((IS_A9LH && !IS_SIGHAX)) { 305 | snprintf(msgA9lh, 64, "fucked up"); 306 | statusA9lh = STATUS_RED; 307 | } 308 | ShowInstallerStatus(); 309 | } 310 | #elif !defined FAIL_TEST 311 | snprintf(msgInstall, 64, "no write mode"); 312 | statusInstall = STATUS_YELLOW; 313 | return 0; 314 | #else 315 | snprintf(msgInstall, 64, "emergency mode"); 316 | statusInstall = STATUS_YELLOW; 317 | ShowInstallerStatus(); 318 | #endif 319 | 320 | 321 | // if we end up here: uhoh 322 | ShowPrompt(false, APP_TITLE " failed!\nThis really should not have happened :/."); 323 | ShowPrompt(false, "Your system is now reverted to\nit's earlier state.\n \nDO NOT TURN OFF YOUR 3DS NOW!"); 324 | 325 | // try to revert to the earlier state 326 | snprintf(msgBackup, 64, "FIRM restore..."); 327 | statusBackup = STATUS_YELLOW; 328 | ShowInstallerStatus(); 329 | ShowProgress(0, 0, "FIRM restore"); 330 | for (u32 i = 0; i < n_firms; i++) { 331 | NandPartitionInfo np_info; 332 | ret = GetNandPartitionInfo(&np_info, NP_TYPE_FIRM, NP_SUBTYPE_CTR, i); 333 | if (ret != 0) break; 334 | u32 fsize = np_info.count * 0x200; 335 | u32 foffset = np_info.sector * 0x200; 336 | char bakname[64]; 337 | snprintf(bakname, 64, NAME_FIRMBACKUP, i); 338 | snprintf(msgBackup, 64, "FIRM restore (%lu/%lu)", i, n_firms); 339 | ShowInstallerStatus(); 340 | if ((f_qread(bakname, WORK_BUFFER, 0, fsize, &bt) != FR_OK) || (bt != fsize) || 341 | (WriteNandBytes(WORK_BUFFER, foffset, fsize, 0xFF) != 0)) { 342 | ret = 1; 343 | break; 344 | } 345 | ShowProgress(i + 1, n_firms, "FIRM restore"); 346 | } 347 | if (ret != 0) { 348 | snprintf(msgBackup, 64, "FIRM restore fail"); 349 | statusBackup = STATUS_RED; 350 | return 1; 351 | } 352 | if ((IS_A9LH && !IS_SIGHAX)) { 353 | snprintf(msgBackup, 64, "0x96 restore..."); 354 | ShowInstallerStatus(); 355 | u8 sector_backup[0x200]; 356 | if ((f_qread(NAME_SECTORBACKUP, sector_backup, 0, 0x200, &bt) != FR_OK) || (bt != 0x200) || 357 | (WriteNandSectors(sector_backup, SECTOR_SECRET, 1, 0xFF) != 0)) { 358 | snprintf(msgBackup, 64, "0x96 restore fail"); 359 | statusBackup = STATUS_RED; 360 | return 1; 361 | } 362 | snprintf(msgA9lh, 64, "restored a9lh"); 363 | statusA9lh = STATUS_YELLOW; 364 | } 365 | snprintf(msgBackup, 64, "backup restored"); 366 | statusBackup = STATUS_YELLOW; 367 | snprintf(msgInstall, 64, "reverted system"); 368 | statusInstall = STATUS_YELLOW; 369 | 370 | 371 | return 1; 372 | } 373 | -------------------------------------------------------------------------------- /source/installer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | u32 ShowInstallerStatus(void); 6 | u32 SafeB9SInstaller(void); 7 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include "installer.h" 2 | #include "ui.h" 3 | #include "i2c.h" 4 | #include "qff.h" 5 | 6 | 7 | void Reboot() 8 | { 9 | i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); 10 | while(true); 11 | } 12 | 13 | 14 | u8 *top_screen, *bottom_screen; 15 | 16 | void main(int argc, char** argv) 17 | { 18 | // Fetch the framebuffer addresses 19 | if(argc >= 2) { 20 | // newer entrypoints 21 | u8 **fb = (u8 **)(void *)argv[1]; 22 | top_screen = fb[0]; 23 | bottom_screen = fb[2]; 24 | } else { 25 | // outdated entrypoints 26 | top_screen = (u8*)(*(u32*)0x23FFFE00); 27 | bottom_screen = (u8*)(*(u32*)0x23FFFE08); 28 | } 29 | ClearScreenF(true, true, COLOR_STD_BG); 30 | u32 ret = SafeB9SInstaller(); 31 | ShowInstallerStatus(); // update installer status one last time 32 | fs_deinit(); 33 | if (ret) ShowPrompt(false, "SigHaxed FIRM was not installed!\nCheck lower screen for info."); 34 | else ShowPrompt(false, "SigHaxed FIRM install success!"); 35 | ClearScreenF(true, true, COLOR_STD_BG); 36 | Reboot(); 37 | } 38 | -------------------------------------------------------------------------------- /source/nand/delay.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .global waitcycles 3 | .type waitcycles STT_FUNC 4 | 5 | @waitcycles ( u32 us ) 6 | waitcycles: 7 | PUSH {R0-R2,LR} 8 | STR R0, [SP,#4] 9 | waitcycles_loop: 10 | LDR R3, [SP,#4] 11 | SUBS R2, R3, #1 12 | STR R2, [SP,#4] 13 | CMP R3, #0 14 | BNE waitcycles_loop 15 | POP {R0-R2,PC} 16 | -------------------------------------------------------------------------------- /source/nand/nand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | // hardcoded start sectors 6 | #define SECTOR_D0K3 0x000001 7 | #define SECTOR_SECRET 0x000096 8 | 9 | // filenames for sector 0x96 10 | #define SECTOR_NAME "sector0x96.bin" 11 | #define SECRET_NAME "secret_sector.bin" 12 | 13 | // 0x110...0x118 in the NAND NCSD header 14 | // see: https://www.3dbrew.org/wiki/NCSD#NCSD_header 15 | #define NP_TYPE_NONE 0 16 | #define NP_TYPE_STD 1 17 | #define NP_TYPE_FAT 2 // this is of our own making 18 | #define NP_TYPE_FIRM 3 19 | #define NP_TYPE_AGB 4 20 | #define NP_TYPE_NCSD 5 // this is of our own making 21 | #define NP_TYPE_D0K3 6 // my own partition ^_^ 22 | #define NP_TYPE_SECRET 7 // this is of our own making 23 | #define NP_TYPE_BONUS 8 // this is of our own making 24 | 25 | // 0x118...0x120 in the NAND NCSD header 26 | // see: https://www.3dbrew.org/wiki/NCSD#NCSD_header 27 | #define NP_SUBTYPE_NONE 0 28 | #define NP_SUBTYPE_TWL 1 29 | #define NP_SUBTYPE_CTR 2 30 | #define NP_SUBTYPE_CTR_N 3 31 | 32 | 33 | typedef struct { 34 | u32 sector; 35 | u32 count; 36 | u32 keyslot; 37 | } __attribute__((packed)) NandPartitionInfo; 38 | 39 | typedef struct { 40 | u32 offset; 41 | u32 size; 42 | } __attribute__((packed)) NandNcsdPartition; 43 | 44 | // see: https://www.3dbrew.org/wiki/NCSD#NCSD_header 45 | typedef struct { 46 | u8 signature[0x100]; 47 | u8 magic[4]; 48 | u32 size; 49 | u64 mediaId; // this is zero 50 | u8 partitions_fs_type[8]; 51 | u8 partitions_crypto_type[8]; 52 | NandNcsdPartition partitions[8]; 53 | u8 unknown[0x5E]; 54 | u8 twl_mbr[0x42]; 55 | } __attribute__((packed)) NandNcsdHeader; 56 | 57 | 58 | bool InitNandCrypto(void); 59 | bool CheckSlot0x05Crypto(void); 60 | bool CheckSector0x96Crypto(void); 61 | bool CheckFirmCrypto(void); 62 | 63 | void CryptNand(void* buffer, u32 sector, u32 count, u32 keyslot); 64 | void CryptSector0x96(void* buffer, bool encrypt); 65 | int ReadNandBytes(void* buffer, u64 offset, u64 count, u32 keyslot); 66 | int WriteNandBytes(const void* buffer, u64 offset, u64 count, u32 keyslot); 67 | int ReadNandSectors(void* buffer, u32 sector, u32 count, u32 keyslot); 68 | int WriteNandSectors(const void* buffer, u32 sector, u32 count, u32 keyslot); 69 | 70 | u32 ValidateNandNcsdHeader(NandNcsdHeader* header); 71 | u32 GetNandNcsdMinSizeSectors(NandNcsdHeader* ncsd); 72 | u32 GetNandMinSizeSectors(void); 73 | u32 GetNandSizeSectors(void); 74 | u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index, NandNcsdHeader* ncsd); 75 | u32 GetNandPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index); 76 | -------------------------------------------------------------------------------- /source/nand/sdmmc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * Copyright (c) 2014-2015, Normmatt 7 | * 8 | * Alternatively, the contents of this file may be used under the terms 9 | * of the GNU General Public License Version 2, as described below: 10 | * 11 | * This file is free software: you may copy, redistribute and/or modify 12 | * it under the terms of the GNU General Public License as published by the 13 | * Free Software Foundation, either version 2 of the License, or (at your 14 | * option) any later version. 15 | * 16 | * This file is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 19 | * Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see http://www.gnu.org/licenses/. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "sdmmc.h" 36 | //#include "DrawCharacter.h" 37 | 38 | #define DATA32_SUPPORT 39 | 40 | #define TRUE 1 41 | #define FALSE 0 42 | 43 | #define NO_INLINE __attribute__ ((noinline)) 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | void waitcycles(uint32_t val); 49 | #ifdef __cplusplus 50 | }; 51 | #endif 52 | 53 | struct mmcdevice handelNAND; 54 | struct mmcdevice handelSD; 55 | 56 | mmcdevice *getMMCDevice(int drive) 57 | { 58 | if(drive==0) return &handelNAND; 59 | return &handelSD; 60 | } 61 | 62 | static int geterror(struct mmcdevice *ctx) 63 | { 64 | return (int)((ctx->error << 29) >> 31); 65 | } 66 | 67 | 68 | static void inittarget(struct mmcdevice *ctx) 69 | { 70 | sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber); 71 | setckl(ctx->clk); 72 | if(ctx->SDOPT == 0) 73 | { 74 | sdmmc_mask16(REG_SDOPT,0,0x8000); 75 | } 76 | else 77 | { 78 | sdmmc_mask16(REG_SDOPT,0x8000,0); 79 | } 80 | 81 | } 82 | 83 | static void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) 84 | { 85 | uint32_t getSDRESP = (cmd << 15) >> 31; 86 | uint16_t flags = (cmd << 15) >> 31; 87 | const int readdata = cmd & 0x20000; 88 | const int writedata = cmd & 0x40000; 89 | 90 | if(readdata || writedata) 91 | { 92 | flags |= TMIO_STAT0_DATAEND; 93 | } 94 | 95 | ctx->error = 0; 96 | while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? 97 | sdmmc_write16(REG_SDIRMASK0,0); 98 | sdmmc_write16(REG_SDIRMASK1,0); 99 | sdmmc_write16(REG_SDSTATUS0,0); 100 | sdmmc_write16(REG_SDSTATUS1,0); 101 | sdmmc_mask16(REG_DATACTL32,0x1800,0); 102 | sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); 103 | sdmmc_write16(REG_SDCMDARG1,args >> 16); 104 | sdmmc_write16(REG_SDCMD,cmd &0xFFFF); 105 | 106 | uint32_t size = ctx->size; 107 | uint8_t *rDataPtr = ctx->rData; 108 | const uint8_t *tDataPtr = ctx->tData; 109 | 110 | int rUseBuf = ( NULL != rDataPtr ); 111 | int tUseBuf = ( NULL != tDataPtr ); 112 | 113 | uint16_t status0 = 0; 114 | while(1) 115 | { 116 | volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); 117 | #ifdef DATA32_SUPPORT 118 | volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); 119 | if((ctl32 & 0x100)) 120 | #else 121 | if((status1 & TMIO_STAT1_RXRDY)) 122 | #endif 123 | { 124 | if(readdata) 125 | { 126 | if(rUseBuf) 127 | { 128 | sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); 129 | if(size > 0x1FF) 130 | { 131 | #ifdef DATA32_SUPPORT 132 | //Gabriel Marcano: This implementation doesn't assume alignment. 133 | //I've removed the alignment check doen with former rUseBuf32 as a result 134 | for(int i = 0; i<0x200; i+=4) 135 | { 136 | uint32_t data = sdmmc_read32(REG_SDFIFO32); 137 | *rDataPtr++ = data; 138 | *rDataPtr++ = data >> 8; 139 | *rDataPtr++ = data >> 16; 140 | *rDataPtr++ = data >> 24; 141 | } 142 | #else 143 | for(int i = 0; i<0x200; i+=2) 144 | { 145 | uint16_t data = sdmmc_read16(REG_SDFIFO); 146 | *rDataPtr++ = data; 147 | *rDataPtr++ = data >> 8; 148 | } 149 | #endif 150 | size -= 0x200; 151 | } 152 | } 153 | 154 | sdmmc_mask16(REG_DATACTL32, 0x800, 0); 155 | } 156 | } 157 | #ifdef DATA32_SUPPORT 158 | if(!(ctl32 & 0x200)) 159 | #else 160 | if((status1 & TMIO_STAT1_TXRQ)) 161 | #endif 162 | { 163 | if(writedata) 164 | { 165 | if(tUseBuf) 166 | { 167 | sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); 168 | if(size > 0x1FF) 169 | { 170 | #ifdef DATA32_SUPPORT 171 | for(int i = 0; i<0x200; i+=4) 172 | { 173 | uint32_t data = *tDataPtr++; 174 | data |= (uint32_t)*tDataPtr++ << 8; 175 | data |= (uint32_t)*tDataPtr++ << 16; 176 | data |= (uint32_t)*tDataPtr++ << 24; 177 | sdmmc_write32(REG_SDFIFO32, data); 178 | } 179 | #else 180 | for(int i = 0; i<0x200; i+=2) 181 | { 182 | uint16_t data = *tDataPtr++; 183 | data |= (uint8_t)(*tDataPtr++ << 8); 184 | sdmmc_write16(REG_SDFIFO, data); 185 | } 186 | #endif 187 | size -= 0x200; 188 | } 189 | } 190 | 191 | sdmmc_mask16(REG_DATACTL32, 0x1000, 0); 192 | } 193 | } 194 | if(status1 & TMIO_MASK_GW) 195 | { 196 | ctx->error |= 4; 197 | break; 198 | } 199 | 200 | if(!(status1 & TMIO_STAT1_CMD_BUSY)) 201 | { 202 | status0 = sdmmc_read16(REG_SDSTATUS0); 203 | if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) 204 | { 205 | ctx->error |= 0x1; 206 | } 207 | if(status0 & TMIO_STAT0_DATAEND) 208 | { 209 | ctx->error |= 0x2; 210 | } 211 | 212 | if((status0 & flags) == flags) 213 | break; 214 | } 215 | } 216 | ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); 217 | ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); 218 | sdmmc_write16(REG_SDSTATUS0,0); 219 | sdmmc_write16(REG_SDSTATUS1,0); 220 | 221 | if(getSDRESP != 0) 222 | { 223 | ctx->ret[0] = (uint32_t)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16)); 224 | ctx->ret[1] = (uint32_t)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16)); 225 | ctx->ret[2] = (uint32_t)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16)); 226 | ctx->ret[3] = (uint32_t)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16)); 227 | } 228 | } 229 | 230 | int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) 231 | { 232 | if(handelSD.isSDHC == 0) sector_no <<= 9; 233 | inittarget(&handelSD); 234 | sdmmc_write16(REG_SDSTOP,0x100); 235 | #ifdef DATA32_SUPPORT 236 | sdmmc_write16(REG_SDBLKCOUNT32,numsectors); 237 | sdmmc_write16(REG_SDBLKLEN32,0x200); 238 | #endif 239 | sdmmc_write16(REG_SDBLKCOUNT,numsectors); 240 | handelSD.tData = in; 241 | handelSD.size = numsectors << 9; 242 | sdmmc_send_command(&handelSD,0x52C19,sector_no); 243 | return geterror(&handelSD); 244 | } 245 | 246 | int NO_INLINE sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) 247 | { 248 | if(handelSD.isSDHC == 0) sector_no <<= 9; 249 | inittarget(&handelSD); 250 | sdmmc_write16(REG_SDSTOP,0x100); 251 | #ifdef DATA32_SUPPORT 252 | sdmmc_write16(REG_SDBLKCOUNT32,numsectors); 253 | sdmmc_write16(REG_SDBLKLEN32,0x200); 254 | #endif 255 | sdmmc_write16(REG_SDBLKCOUNT,numsectors); 256 | handelSD.rData = out; 257 | handelSD.size = numsectors << 9; 258 | sdmmc_send_command(&handelSD,0x33C12,sector_no); 259 | return geterror(&handelSD); 260 | } 261 | 262 | 263 | 264 | int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) 265 | { 266 | if(handelNAND.isSDHC == 0) sector_no <<= 9; 267 | inittarget(&handelNAND); 268 | sdmmc_write16(REG_SDSTOP,0x100); 269 | #ifdef DATA32_SUPPORT 270 | sdmmc_write16(REG_SDBLKCOUNT32,numsectors); 271 | sdmmc_write16(REG_SDBLKLEN32,0x200); 272 | #endif 273 | sdmmc_write16(REG_SDBLKCOUNT,numsectors); 274 | handelNAND.rData = out; 275 | handelNAND.size = numsectors << 9; 276 | sdmmc_send_command(&handelNAND,0x33C12,sector_no); 277 | return geterror(&handelNAND); 278 | } 279 | 280 | int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) //experimental 281 | { 282 | if(handelNAND.isSDHC == 0) sector_no <<= 9; 283 | inittarget(&handelNAND); 284 | sdmmc_write16(REG_SDSTOP,0x100); 285 | #ifdef DATA32_SUPPORT 286 | sdmmc_write16(REG_SDBLKCOUNT32,numsectors); 287 | sdmmc_write16(REG_SDBLKLEN32,0x200); 288 | #endif 289 | sdmmc_write16(REG_SDBLKCOUNT,numsectors); 290 | handelNAND.tData = in; 291 | handelNAND.size = numsectors << 9; 292 | sdmmc_send_command(&handelNAND,0x52C19,sector_no); 293 | return geterror(&handelNAND); 294 | } 295 | 296 | static uint32_t calcSDSize(uint8_t* csd, int type) 297 | { 298 | uint32_t result = 0; 299 | if(type == -1) type = csd[14] >> 6; 300 | switch(type) 301 | { 302 | case 0: 303 | { 304 | uint32_t block_len=csd[9]&0xf; 305 | block_len=1u<>7)|((csd[5]&3)<<1)); 307 | mult=1u<<(mult+2); 308 | result=csd[8]&3; 309 | result=(result<<8)|csd[7]; 310 | result=(result<<2)|(csd[6]>>6); 311 | result=(result+1)*mult*block_len/512; 312 | } 313 | break; 314 | case 1: 315 | result=csd[7]&0x3f; 316 | result=(result<<8)|csd[6]; 317 | result=(result<<8)|csd[5]; 318 | result=(result+1)*1024; 319 | break; 320 | default: 321 | break; //Do nothing otherwise FIXME perhaps return some error? 322 | } 323 | return result; 324 | } 325 | 326 | void InitSD() 327 | { 328 | //sdmmc_mask16(0x100,0x800,0); 329 | //sdmmc_mask16(0x100,0x1000,0); 330 | //sdmmc_mask16(0x100,0x0,0x402); 331 | //sdmmc_mask16(0xD8,0x22,0x2); 332 | //sdmmc_mask16(0x100,0x2,0); 333 | //sdmmc_mask16(0xD8,0x22,0); 334 | //sdmmc_write16(0x104,0); 335 | //sdmmc_write16(0x108,1); 336 | //sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this 337 | //sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this 338 | //sdmmc_mask16(0x20,0,0x31D); 339 | //sdmmc_mask16(0x22,0,0x837F); 340 | //sdmmc_mask16(0xFC,0,0xDB); 341 | //sdmmc_mask16(0xFE,0,0xDB); 342 | ////sdmmc_write16(REG_SDCLKCTL,0x20); 343 | ////sdmmc_write16(REG_SDOPT,0x40EE); 344 | ////sdmmc_mask16(0x02,0x3,0); 345 | //sdmmc_write16(REG_SDCLKCTL,0x40); 346 | //sdmmc_write16(REG_SDOPT,0x40EB); 347 | //sdmmc_mask16(0x02,0x3,0); 348 | //sdmmc_write16(REG_SDBLKLEN,0x200); 349 | //sdmmc_write16(REG_SDSTOP,0); 350 | 351 | *(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32 352 | *(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32 353 | #ifdef DATA32_SUPPORT 354 | *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 355 | #else 356 | *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 357 | #endif 358 | *(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2; 359 | #ifdef DATA32_SUPPORT 360 | *(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32 361 | *(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL 362 | *(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32 363 | #else 364 | *(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32 365 | *(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL 366 | *(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32 367 | #endif 368 | *(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32 369 | *(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET 370 | *(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET 371 | *(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 372 | *(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 373 | *(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 374 | *(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 375 | *(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL 376 | #ifdef DATA32_SUPPORT 377 | *(volatile uint16_t*)0x10006024 = 0x20; 378 | *(volatile uint16_t*)0x10006028 = 0x40EE; 379 | #else 380 | *(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20 381 | *(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE 382 | #endif 383 | *(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL 384 | *(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN 385 | *(volatile uint16_t*)0x10006008 = 0; //SDSTOP 386 | } 387 | 388 | int Nand_Init() 389 | { 390 | //NAND 391 | handelNAND.isSDHC = 0; 392 | handelNAND.SDOPT = 0; 393 | handelNAND.res = 0; 394 | handelNAND.initarg = 1; 395 | handelNAND.clk = 0x80; 396 | handelNAND.devicenumber = 1; 397 | 398 | inittarget(&handelNAND); 399 | waitcycles(0xF000); 400 | 401 | sdmmc_send_command(&handelNAND,0,0); 402 | 403 | do 404 | { 405 | do 406 | { 407 | sdmmc_send_command(&handelNAND,0x10701,0x100000); 408 | } while ( !(handelNAND.error & 1) ); 409 | } 410 | while((handelNAND.ret[0] & 0x80000000) == 0); 411 | 412 | sdmmc_send_command(&handelNAND,0x10602,0x0); 413 | if((handelNAND.error & 0x4))return -1; 414 | 415 | sdmmc_send_command(&handelNAND,0x10403,handelNAND.initarg << 0x10); 416 | if((handelNAND.error & 0x4))return -1; 417 | 418 | sdmmc_send_command(&handelNAND,0x10609,handelNAND.initarg << 0x10); 419 | if((handelNAND.error & 0x4))return -1; 420 | 421 | handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0],0); 422 | handelNAND.clk = 1; 423 | setckl(1); 424 | 425 | sdmmc_send_command(&handelNAND,0x10407,handelNAND.initarg << 0x10); 426 | if((handelNAND.error & 0x4))return -1; 427 | 428 | handelNAND.SDOPT = 1; 429 | 430 | sdmmc_send_command(&handelNAND,0x10506,0x3B70100); 431 | if((handelNAND.error & 0x4))return -1; 432 | 433 | sdmmc_send_command(&handelNAND,0x10506,0x3B90100); 434 | if((handelNAND.error & 0x4))return -1; 435 | 436 | sdmmc_send_command(&handelNAND,0x1040D,handelNAND.initarg << 0x10); 437 | if((handelNAND.error & 0x4))return -1; 438 | 439 | sdmmc_send_command(&handelNAND,0x10410,0x200); 440 | if((handelNAND.error & 0x4))return -1; 441 | 442 | handelNAND.clk |= 0x200; 443 | 444 | inittarget(&handelSD); 445 | 446 | return 0; 447 | } 448 | 449 | int SD_Init() 450 | { 451 | //SD 452 | handelSD.isSDHC = 0; 453 | handelSD.SDOPT = 0; 454 | handelSD.res = 0; 455 | handelSD.initarg = 0; 456 | handelSD.clk = 0x80; 457 | handelSD.devicenumber = 0; 458 | 459 | inittarget(&handelSD); 460 | 461 | waitcycles(1u << 22); //Card needs a little bit of time to be detected, it seems FIXME test again to see what a good number is for the delay 462 | 463 | //If not inserted 464 | if (!(*((volatile uint16_t*)(SDMMC_BASE + REG_SDSTATUS0)) & TMIO_STAT0_SIGSTATE)) return 5; 465 | 466 | sdmmc_send_command(&handelSD,0,0); 467 | sdmmc_send_command(&handelSD,0x10408,0x1AA); 468 | uint32_t temp = (handelSD.error & 0x1) << 0x1E; 469 | 470 | uint32_t temp2 = 0; 471 | do 472 | { 473 | do 474 | { 475 | sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); 476 | sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp); 477 | temp2 = 1; 478 | } while ( !(handelSD.error & 1) ); 479 | } 480 | while((handelSD.ret[0] & 0x80000000) == 0); 481 | 482 | if(!((handelSD.ret[0] >> 30) & 1) || !temp) 483 | temp2 = 0; 484 | 485 | handelSD.isSDHC = temp2; 486 | 487 | sdmmc_send_command(&handelSD,0x10602,0); 488 | if((handelSD.error & 0x4)) return -1; 489 | 490 | sdmmc_send_command(&handelSD,0x10403,0); 491 | if((handelSD.error & 0x4)) return -2; 492 | handelSD.initarg = handelSD.ret[0] >> 0x10; 493 | 494 | sdmmc_send_command(&handelSD,0x10609,handelSD.initarg << 0x10); 495 | if((handelSD.error & 0x4)) return -3; 496 | 497 | handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0],-1); 498 | handelSD.clk = 1; 499 | setckl(1); 500 | 501 | sdmmc_send_command(&handelSD,0x10507,handelSD.initarg << 0x10); 502 | if((handelSD.error & 0x4)) return -4; 503 | 504 | sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); 505 | if((handelSD.error & 0x4)) return -5; 506 | 507 | handelSD.SDOPT = 1; 508 | sdmmc_send_command(&handelSD,0x10446,0x2); 509 | if((handelSD.error & 0x4)) return -6; 510 | 511 | sdmmc_send_command(&handelSD,0x1040D,handelSD.initarg << 0x10); 512 | if((handelSD.error & 0x4)) return -7; 513 | 514 | sdmmc_send_command(&handelSD,0x10410,0x200); 515 | if((handelSD.error & 0x4)) return -8; 516 | handelSD.clk |= 0x200; 517 | 518 | return 0; 519 | } 520 | 521 | int sdmmc_get_cid(bool isNand, uint32_t *info) 522 | { 523 | struct mmcdevice *device; 524 | if(isNand) 525 | device = &handelNAND; 526 | else 527 | device = &handelSD; 528 | 529 | inittarget(device); 530 | // use cmd7 to put sd card in standby mode 531 | // CMD7 532 | { 533 | sdmmc_send_command(device,0x10507,0); 534 | //if((device->error & 0x4)) return -1; 535 | } 536 | 537 | // get sd card info 538 | // use cmd10 to read CID 539 | { 540 | sdmmc_send_command(device,0x1060A,device->initarg << 0x10); 541 | //if((device->error & 0x4)) return -2; 542 | 543 | for( int i = 0; i < 4; ++i ) { 544 | info[i] = device->ret[i]; 545 | } 546 | } 547 | 548 | // put sd card back to transfer mode 549 | // CMD7 550 | { 551 | sdmmc_send_command(device,0x10507,device->initarg << 0x10); 552 | //if((device->error & 0x4)) return -3; 553 | } 554 | 555 | return 0; 556 | } 557 | 558 | int sdmmc_sdcard_init() 559 | { 560 | InitSD(); 561 | int nand_res = Nand_Init(); 562 | int sd_res = SD_Init(); 563 | return nand_res | sd_res; 564 | } 565 | -------------------------------------------------------------------------------- /source/nand/sdmmc.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDMMC_H__ 2 | #define __SDMMC_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define SDMMC_BASE 0x10006000 8 | 9 | #define REG_SDCMD 0x00 10 | #define REG_SDPORTSEL 0x02 11 | #define REG_SDCMDARG 0x04 12 | #define REG_SDCMDARG0 0x04 13 | #define REG_SDCMDARG1 0x06 14 | #define REG_SDSTOP 0x08 15 | #define REG_SDBLKCOUNT 0x0a 16 | 17 | #define REG_SDRESP0 0x0c 18 | #define REG_SDRESP1 0x0e 19 | #define REG_SDRESP2 0x10 20 | #define REG_SDRESP3 0x12 21 | #define REG_SDRESP4 0x14 22 | #define REG_SDRESP5 0x16 23 | #define REG_SDRESP6 0x18 24 | #define REG_SDRESP7 0x1a 25 | 26 | #define REG_SDSTATUS0 0x1c 27 | #define REG_SDSTATUS1 0x1e 28 | 29 | #define REG_SDIRMASK0 0x20 30 | #define REG_SDIRMASK1 0x22 31 | #define REG_SDCLKCTL 0x24 32 | 33 | #define REG_SDBLKLEN 0x26 34 | #define REG_SDOPT 0x28 35 | #define REG_SDFIFO 0x30 36 | 37 | #define REG_DATACTL 0xd8 38 | #define REG_SDRESET 0xe0 39 | #define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? 40 | 41 | #define REG_DATACTL32 0x100 42 | #define REG_SDBLKLEN32 0x104 43 | #define REG_SDBLKCOUNT32 0x108 44 | #define REG_SDFIFO32 0x10C 45 | 46 | #define REG_CLK_AND_WAIT_CTL 0x138 47 | #define REG_RESET_SDIO 0x1e0 48 | 49 | #define TMIO_STAT0_CMDRESPEND 0x0001 50 | #define TMIO_STAT0_DATAEND 0x0004 51 | #define TMIO_STAT0_CARD_REMOVE 0x0008 52 | #define TMIO_STAT0_CARD_INSERT 0x0010 53 | #define TMIO_STAT0_SIGSTATE 0x0020 54 | #define TMIO_STAT0_WRPROTECT 0x0080 55 | #define TMIO_STAT0_CARD_REMOVE_A 0x0100 56 | #define TMIO_STAT0_CARD_INSERT_A 0x0200 57 | #define TMIO_STAT0_SIGSTATE_A 0x0400 58 | #define TMIO_STAT1_CMD_IDX_ERR 0x0001 59 | #define TMIO_STAT1_CRCFAIL 0x0002 60 | #define TMIO_STAT1_STOPBIT_ERR 0x0004 61 | #define TMIO_STAT1_DATATIMEOUT 0x0008 62 | #define TMIO_STAT1_RXOVERFLOW 0x0010 63 | #define TMIO_STAT1_TXUNDERRUN 0x0020 64 | #define TMIO_STAT1_CMDTIMEOUT 0x0040 65 | #define TMIO_STAT1_RXRDY 0x0100 66 | #define TMIO_STAT1_TXRQ 0x0200 67 | #define TMIO_STAT1_ILL_FUNC 0x2000 68 | #define TMIO_STAT1_CMD_BUSY 0x4000 69 | #define TMIO_STAT1_ILL_ACCESS 0x8000 70 | 71 | #define TMIO_MASK_ALL 0x837f031d 72 | 73 | #define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ 74 | TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) 75 | 76 | #define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) 77 | #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) 78 | 79 | #ifdef __cplusplus 80 | extern "C" { 81 | #endif 82 | 83 | typedef struct mmcdevice { 84 | uint8_t* rData; 85 | const uint8_t* tData; 86 | uint32_t size; 87 | uint32_t error; 88 | uint16_t stat0; 89 | uint16_t stat1; 90 | uint32_t ret[4]; 91 | uint32_t initarg; 92 | uint32_t isSDHC; 93 | uint32_t clk; 94 | uint32_t SDOPT; 95 | uint32_t devicenumber; 96 | uint32_t total_size; //size in sectors of the device 97 | uint32_t res; 98 | } mmcdevice; 99 | 100 | int sdmmc_sdcard_init(); 101 | int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out); 102 | int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); 103 | int sdmmc_sdcard_writesector(uint32_t sector_no, const uint8_t *in); 104 | int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); 105 | 106 | int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); 107 | int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); 108 | 109 | int sdmmc_get_cid(bool isNand, uint32_t *info); 110 | 111 | mmcdevice *getMMCDevice(int drive); 112 | 113 | void InitSD(); 114 | int Nand_Init(); 115 | int SD_Init(); 116 | 117 | #ifdef __cplusplus 118 | }; 119 | #endif 120 | 121 | //--------------------------------------------------------------------------------- 122 | static inline uint16_t sdmmc_read16(uint16_t reg) { 123 | //--------------------------------------------------------------------------------- 124 | return *(volatile uint16_t*)(SDMMC_BASE + reg); 125 | } 126 | 127 | //--------------------------------------------------------------------------------- 128 | static inline void sdmmc_write16(uint16_t reg, uint16_t val) { 129 | //--------------------------------------------------------------------------------- 130 | *(volatile uint16_t*)(SDMMC_BASE + reg) = val; 131 | } 132 | 133 | //--------------------------------------------------------------------------------- 134 | static inline uint32_t sdmmc_read32(uint16_t reg) { 135 | //--------------------------------------------------------------------------------- 136 | return *(volatile uint32_t*)(SDMMC_BASE + reg); 137 | } 138 | 139 | //--------------------------------------------------------------------------------- 140 | static inline void sdmmc_write32(uint16_t reg, uint32_t val) { 141 | //--------------------------------------------------------------------------------- 142 | *(volatile uint32_t*)(SDMMC_BASE + reg) = val; 143 | } 144 | 145 | //--------------------------------------------------------------------------------- 146 | static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) { 147 | //--------------------------------------------------------------------------------- 148 | uint16_t val = sdmmc_read16(reg); 149 | val &= ~clear; 150 | val |= set; 151 | sdmmc_write16(reg, val); 152 | } 153 | 154 | static inline void setckl(uint32_t data) 155 | { 156 | sdmmc_mask16(REG_SDCLKCTL,0x100,0); 157 | sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF); 158 | sdmmc_mask16(REG_SDCLKCTL,0x0,0x100); 159 | } 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /source/safety/safewrite.c: -------------------------------------------------------------------------------- 1 | #include "safewrite.h" 2 | #include "nand.h" 3 | #include "sha.h" 4 | 5 | // safe file writer function, warnings: 6 | // (1) file must be opened in RW mode for this to work 7 | // (2) contents of buffer may change on corruption 8 | // (3) uses SHA register 9 | u32 SafeWriteFile(FIL* file, void* buff, FSIZE_t ofs, UINT btw) { 10 | u8 sha_in[0x20]; 11 | UINT bw; 12 | 13 | sha_quick(sha_in, buff, btw, SHA256_MODE); 14 | if ((f_lseek(file, ofs) != FR_OK) || (f_write(file, buff, btw, &bw) != FR_OK) || (btw != bw) || 15 | (f_lseek(file, ofs) != FR_OK) || (f_read(file, buff, btw, &bw) != FR_OK) || (btw != bw)) 16 | return 1; 17 | 18 | return (sha_cmp(sha_in, buff, btw, SHA256_MODE) == 0) ? 0 : 1; 19 | } 20 | 21 | // safe file quick writer function 22 | // same as SafeWriteFile(), but also handles filec reate, too, same warnings apply 23 | u32 SafeQWriteFile(const TCHAR* path, void* buff, UINT btw) { 24 | FIL fp; 25 | u32 ret = 0; 26 | if (f_open(&fp, path, FA_READ|FA_WRITE|FA_CREATE_ALWAYS) != FR_OK) 27 | return 1; 28 | ret = SafeWriteFile(&fp, buff, 0, btw); 29 | f_close(&fp); 30 | return ret; 31 | } 32 | 33 | // safe NAND writer function, warnings: 34 | // (1) contents of buffer may change on corruption 35 | // (2) uses SHA register 36 | u32 SafeWriteNand(void* buff, u32 ofs, u32 btw, u32 keyslot) { 37 | u8 sha_in[0x20]; 38 | 39 | sha_quick(sha_in, buff, btw, SHA256_MODE); 40 | if ((WriteNandBytes(buff, ofs, btw, keyslot) != 0) || (ReadNandBytes(buff, ofs, btw, keyslot) != 0)) 41 | return 1; 42 | 43 | return (sha_cmp(sha_in, buff, btw, SHA256_MODE) == 0) ? 0 : 1; 44 | } -------------------------------------------------------------------------------- /source/safety/safewrite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | #include "ff.h" 5 | 6 | u32 SafeWriteFile(FIL* file, void* buff, FSIZE_t ofs, UINT btw); 7 | u32 SafeQWriteFile(const TCHAR* path, void* buff, UINT btw); 8 | u32 SafeWriteNand(void* buff, u32 ofs, u32 btw, u32 keyslot); 9 | -------------------------------------------------------------------------------- /source/safety/validator.c: -------------------------------------------------------------------------------- 1 | #include "validator.h" 2 | #include "unittype.h" 3 | #include "sha.h" 4 | 5 | #define FIRM_MAGIC 'F', 'I', 'R', 'M' 6 | #define FIRM_MAX_SIZE 0x400000 // 4MB, due to FIRM partition size 7 | 8 | #define B9S_MAGIC "B9S" 9 | #define B9S_OFFSET (0x40 - strnlen(B9S_MAGIC, 0x10)) 10 | 11 | #define FB3_MAGIC "FASTBOOT 3DS " 12 | #define FB3_OFFSET 0x200 // this is not actually used 13 | 14 | // see: https://www.3dbrew.org/wiki/FIRM#Firmware_Section_Headers 15 | typedef struct { 16 | u32 offset; 17 | u32 address; 18 | u32 size; 19 | u32 type; 20 | u8 hash[0x20]; 21 | } __attribute__((packed)) FirmSectionHeader; 22 | 23 | // see: https://www.3dbrew.org/wiki/FIRM#FIRM_Header 24 | typedef struct { 25 | u8 magic[4]; 26 | u8 priority[4]; 27 | u32 entry_arm11; 28 | u32 entry_arm9; 29 | u8 reserved1[0x30]; 30 | FirmSectionHeader sections[4]; 31 | u8 signature[0x100]; 32 | } __attribute__((packed, aligned(16))) FirmHeader; 33 | 34 | // from: https://github.com/AuroraWright/SafeA9LHInstaller/blob/master/source/installer.c#L9-L17 35 | const u8 sectorHash[0x20] = { 36 | 0x82, 0xF2, 0x73, 0x0D, 0x2C, 0x2D, 0xA3, 0xF3, 0x01, 0x65, 0xF9, 0x87, 0xFD, 0xCC, 0xAC, 0x5C, 37 | 0xBA, 0xB2, 0x4B, 0x4E, 0x5F, 0x65, 0xC9, 0x81, 0xCD, 0x7B, 0xE6, 0xF4, 0x38, 0xE6, 0xD9, 0xD3 38 | }; 39 | 40 | // from: https://github.com/SciresM/CTRAesEngine/tree/master/CTRAesEngine/Resources/_byte 41 | const u8 sectorHash_dev[0x20] = { 42 | 0xB2, 0x91, 0xD9, 0xB1, 0x33, 0x05, 0x79, 0x0D, 0x47, 0xC6, 0x06, 0x98, 0x4C, 0x67, 0xC3, 0x70, 43 | 0x09, 0x54, 0xE3, 0x85, 0xDE, 0x47, 0x55, 0xAF, 0xC6, 0xCB, 0x1D, 0x8D, 0xC7, 0x84, 0x5A, 0x64 44 | }; 45 | 46 | // sighax signature hash - thanks go to Myria & SciresM for bruteforcing this 47 | const u8 sighaxHash[0x20] = { 48 | 0x07, 0x8C, 0xC0, 0xCF, 0xD8, 0x50, 0xA2, 0x70, 0x93, 0xDD, 0xA2, 0x63, 0x0C, 0x36, 0x03, 0xCA, 49 | 0x0C, 0x96, 0x96, 0x9B, 0xD1, 0xF2, 0x6D, 0xA4, 0x8A, 0xC7, 0xB1, 0xBA, 0xE5, 0xDD, 0x52, 0x19 50 | }; 51 | 52 | // sighax dev signature hash - thanks go to Myria & SciresM for bruteforcing this 53 | const u8 sighaxHash_dev[0x20] = { 54 | 0xE6, 0x35, 0xC6, 0x36, 0xDC, 0x62, 0x59, 0xD6, 0x22, 0x8A, 0xF5, 0xBE, 0xD2, 0x84, 0x6E, 0x33, 55 | 0x96, 0xD3, 0x78, 0x6E, 0xDF, 0x50, 0x3D, 0x11, 0x86, 0x84, 0x01, 0x59, 0x97, 0x50, 0x42, 0x26 56 | }; 57 | 58 | // see: http://www.sighax.com/ 59 | const u8 sighaxHash_alt[0x20] = { 60 | 0xAD, 0xB7, 0x3A, 0xBC, 0x35, 0x70, 0x8E, 0xF1, 0xDF, 0xE9, 0xEF, 0x9C, 0xA5, 0xFA, 0xC8, 0xBF, 61 | 0xC2, 0xDF, 0x91, 0x6B, 0xB2, 0xE3, 0x81, 0x01, 0x85, 0x84, 0x82, 0x40, 0x9F, 0x0D, 0x45, 0x0A 62 | }; 63 | 64 | u32 ValidateFirmHeader(FirmHeader* header, u32 data_size) { 65 | u8 magic[] = { FIRM_MAGIC }; 66 | if (memcmp(header->magic, magic, sizeof(magic)) != 0) 67 | return 1; 68 | 69 | u32 firm_size = sizeof(FirmHeader); 70 | for (u32 i = 0; i < 4; i++) { 71 | FirmSectionHeader* section = header->sections + i; 72 | if (!section->size) continue; 73 | if (section->offset < firm_size) return 1; 74 | firm_size = section->offset + section->size; 75 | } 76 | 77 | if ((firm_size > FIRM_MAX_SIZE) || (data_size && (firm_size > data_size))) 78 | return 1; 79 | 80 | return 0; 81 | } 82 | 83 | u32 ValidateFirm(void* firm, u8* firm_sha, u32 firm_size, char* output) { 84 | FirmHeader* header = (FirmHeader*) firm; 85 | int section_arm11 = -1; 86 | int section_arm9 = -1; 87 | 88 | // validate firm header 89 | if (ValidateFirmHeader(header, firm_size) != 0) 90 | return 1; 91 | 92 | // hash verify all available sections 93 | for (u32 i = 0; i < 4; i++) { 94 | FirmSectionHeader* section = header->sections + i; 95 | if (!section->size) continue; 96 | if (sha_cmp(section->hash, (u8*) firm + section->offset, section->size, SHA256_MODE) != 0) { 97 | if (output) snprintf(output, 64, "Section %lu hash mismatch", i); 98 | return 1; 99 | } 100 | if ((header->entry_arm11 >= section->address) && 101 | (header->entry_arm11 < section->address + section->size)) 102 | section_arm11 = i; 103 | if ((header->entry_arm9 >= section->address) && 104 | (header->entry_arm9 < section->address + section->size)) 105 | section_arm9 = i; 106 | } 107 | 108 | // sections for arm11 / arm9 entrypoints not found? 109 | if ((section_arm11 < 0) || (section_arm9 < 0)) { 110 | if (output) snprintf(output, 64, "ARM11/ARM9 entrypoints not found"); 111 | return 1; 112 | } 113 | 114 | // check provided .SHA 115 | if (sha_cmp(firm_sha, firm, firm_size, SHA256_MODE) != 0) { 116 | if (output) snprintf(output, 64, "SHA hash mismatch"); 117 | return 1; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | u32 ValidateSector(void* sector) { 124 | return (sha_cmp((IS_DEVKIT) ? sectorHash_dev : sectorHash, sector, 0x200, SHA256_MODE) == 0) ? 0 : 1; 125 | } 126 | 127 | u32 CheckFirmSigHax(void* firm) { 128 | FirmHeader* header = (FirmHeader*) firm; 129 | return ((sha_cmp((IS_DEVKIT) ? sighaxHash_dev : sighaxHash, header->signature, 0x100, SHA256_MODE) == 0) || 130 | (!IS_DEVKIT && (sha_cmp(sighaxHash_alt, header->signature, 0x100, SHA256_MODE) == 0))) ? 0 : 1; 131 | } 132 | 133 | u32 CheckBoot9Strap(void* firm) { 134 | return (memcmp(((u8*) firm) + B9S_OFFSET, B9S_MAGIC, strnlen(B9S_MAGIC, 0x10)) == 0) ? 0 : 1; 135 | } 136 | 137 | u32 CheckFastBoot3DS(void* firm) { 138 | FirmHeader* header = (FirmHeader*) firm; 139 | u32 offset = 0; 140 | for (u32 i = 0; (i < 4) && !offset; i++) { // find ARM9 section 141 | FirmSectionHeader* section = header->sections + i; 142 | if (section->size && (section->type == 0)) 143 | offset = section->offset; 144 | } 145 | return (offset && (memcmp(((u8*) firm) + offset, FB3_MAGIC, strnlen(FB3_MAGIC, 0x10)) == 0)) ? 0 : 1; 146 | } 147 | 148 | u32 CheckFirmPayload(void* firm, char* result) { 149 | if (CheckBoot9Strap(firm) == 0) { 150 | if (result) snprintf(result, 32, "boot9strap firm"); 151 | return 0; 152 | #ifdef OPEN_INSTALLER 153 | } else if (CheckFastBoot3DS(firm) == 0) { 154 | if (result) snprintf(result, 32, "fastboot3ds firm"); 155 | return 0; 156 | #endif 157 | } 158 | if (result) snprintf(result, 32, "unknown firm"); 159 | return 1; 160 | } 161 | -------------------------------------------------------------------------------- /source/safety/validator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.h" 4 | 5 | u32 ValidateFirm(void* firm, u8* firm_sha, u32 firm_size, char* output); 6 | u32 ValidateSector(void* sector); 7 | u32 CheckFirmSigHax(void* firm); 8 | u32 CheckFirmPayload(void* firm, char* result); 9 | -------------------------------------------------------------------------------- /source/start.s: -------------------------------------------------------------------------------- 1 | .section .text.start 2 | .global _start 3 | .align 4 4 | .arm 5 | 6 | @ if the binary is booted from Brahma/CakeHax/k9lh 7 | @ the entrypoint is 8 | @ framebuffers are already set 9 | _start: 10 | nop 11 | nop 12 | nop 13 | nop 14 | nop 15 | nop 16 | nop 17 | nop 18 | nop 19 | nop 20 | nop @ dummy 21 | b _skip_gw 22 | 23 | @ if the binary is booted from the GW exploit 24 | @ the entrypoint is 25 | _start_gw: 26 | 27 | @@wait for the arm11 kernel threads to be ready 28 | mov r1, #0x10000 29 | waitLoop9: 30 | sub r1, #1 31 | cmp r1, #0 32 | bgt waitLoop9 33 | 34 | mov r1, #0x10000 35 | waitLoop92: 36 | sub r1, #1 37 | cmp r1, #0 38 | bgt waitLoop92 39 | 40 | 41 | @ copy the payload to the standard entrypoint (0x23F00000) 42 | adr r0, _start 43 | add r1, r0, #0x100000 44 | ldr r2, .entry 45 | .copy_binary_fcram: 46 | cmp r0, r1 47 | ldrlt r3, [r0], #4 48 | strlt r3, [r2], #4 49 | blt .copy_binary_fcram 50 | 51 | @ setup framebuffers to look like Brahma/etc 52 | 53 | ldr r0, .gw_fba 54 | ldr r1, [r0, #0x18] 55 | and r1, #1 56 | ldr r1, [r0, r1, lsl #2] @ r1 := top framebuffer loc 57 | mov r2, r1 @ r2 := top framebuffer loc 58 | 59 | ldr r0, .gw_fbb 60 | ldr r3, [r0, #0xC] 61 | and r3, #1 62 | ldr r3, [r0, r3, lsl #2] @ r3 := bottom framebuffer loc 63 | 64 | ldr r0, .cakehax 65 | stmia r0, {r1,r2,r3} 66 | @ framebuffers properly set 67 | 68 | ldr r3, =0xFFFF0830 @ flush (clean & invalidate) entire dcache b9 func 69 | blx r3 70 | 71 | mov r3, #0 72 | mcr p15, 0, r3, c7, c5, 0 @ invalidate I-cache 73 | 74 | mov r2, #0 75 | ldr r3, .entry 76 | bx r3 77 | 78 | .gw_fba: .word 0x080FFFC0 79 | .gw_fbb: .word 0x080FFFD0 80 | .cakehax: .word 0x23FFFE00 81 | .entry: .word 0x23F00000 82 | 83 | _skip_gw: 84 | mov r9, r0 @ argc 85 | mov r10, r1 @ argv 86 | 87 | ldr r4, =0xBEEF 88 | lsl r2, #16 89 | lsr r2, #16 90 | cmp r2, r4 @ magic word 91 | movne r9, #0 92 | 93 | @ Disable caches / mpu 94 | mrc p15, 0, r4, c1, c0, 0 @ read control register 95 | bic r4, #(1<<16) @ - dtcm disable (mandated by the docs, before you change the dtcm's address) 96 | bic r4, #(1<<12) @ - instruction cache disable 97 | bic r4, #(1<<2) @ - data cache disable 98 | bic r4, #(1<<0) @ - mpu disable 99 | mcr p15, 0, r4, c1, c0, 0 @ write control register 100 | 101 | @ Disable FIQs and IRQs 102 | msr cpsr_cxsf, #0xD3 @ PSR_SVC_MODE | PSR_I | PSR_F 103 | 104 | @ Disable and acknowledge interrupts 105 | mov r2, #0x10000000 106 | add r2, r2, #0x1000 107 | mov r0, #0 108 | mvn r1, #0 @ 0xFFFFFFFF 109 | strd r0, r1, [r2] @ REG_IE/IF 110 | 111 | @ Clear NDMA registers 112 | add r2, r2, #0x1000 @ NDMA_GLOBAL_CNT, 0x10002000 = 0x10001000 + 0x1000 113 | add r1, r2, #0xFC 114 | add r2, r2, #0x1C 115 | dma_clear_loop: 116 | str r0, [r2], #0x1C 117 | cmp r1, r2 118 | bne dma_clear_loop 119 | 120 | @ Clear bss 121 | ldr r0, =__bss_start 122 | ldr r1, =__bss_end 123 | mov r2, #0 124 | 125 | .bss_clr: 126 | cmp r0, r1 127 | strlt r2, [r0], #4 128 | blt .bss_clr 129 | 130 | @ Invalidate caches 131 | mov r5, #0 132 | mcr p15, 0, r5, c7, c5, 0 @ invalidate I-cache 133 | mcr p15, 0, r5, c7, c6, 0 @ invalidate D-cache 134 | mcr p15, 0, r5, c7, c10, 4 @ drain write buffer 135 | 136 | @ Give read/write access to all the memory regions 137 | ldr r5, =0x33333333 138 | mcr p15, 0, r5, c5, c0, 2 @ write data access 139 | mcr p15, 0, r5, c5, c0, 3 @ write instruction access 140 | 141 | @ Sets MPU permissions and cache settings 142 | ldr r0, =0xFFFF001F @ ffff0000 64k | bootrom (unprotected / protected) 143 | ldr r1, =0x3000801B @ 30000000 16k | dtcm 144 | ldr r2, =0x01FF801D @ 01ff8000 32k | itcm 145 | ldr r3, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS) 146 | ldr r4, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB) 147 | ldr r5, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS) 148 | ldr r6, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram 149 | ldr r7, =0x1800002D @ 18000000 8M | vram (+ 2MB) 150 | mov r8, #0x2D 151 | mcr p15, 0, r0, c6, c0, 0 152 | mcr p15, 0, r1, c6, c1, 0 153 | mcr p15, 0, r2, c6, c2, 0 154 | mcr p15, 0, r3, c6, c3, 0 155 | mcr p15, 0, r4, c6, c4, 0 156 | mcr p15, 0, r5, c6, c5, 0 157 | mcr p15, 0, r6, c6, c6, 0 158 | mcr p15, 0, r7, c6, c7, 0 159 | mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 5 160 | mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 5 161 | mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 5 162 | 163 | @ Enable dctm 164 | ldr r1, =0x3000800A @ set dtcm 165 | mcr p15, 0, r1, c9, c1, 0 @ set the dtcm Region Register 166 | 167 | @ Enable caches 168 | mrc p15, 0, r4, c1, c0, 0 @ read control register 169 | orr r4, r4, #(1<<18) @ - itcm enable 170 | orr r4, r4, #(1<<16) @ - dtcm enable 171 | orr r4, r4, #(1<<12) @ - instruction cache enable 172 | orr r4, r4, #(1<<2) @ - data cache enable 173 | orr r4, r4, #(1<<0) @ - mpu enable 174 | mcr p15, 0, r4, c1, c0, 0 @ write control register 175 | 176 | @ Fixes mounting of SDMC 177 | ldr r0, =0x10000020 178 | mov r1, #0x340 179 | str r1, [r0] 180 | 181 | ldr sp, =0x23F00000 182 | 183 | mov r0, r9 184 | mov r1, r10 185 | b main 186 | 187 | .pool 188 | --------------------------------------------------------------------------------