├── .gitignore ├── FlashMeInjector ├── Makefile ├── flashme.nds └── source │ └── main.c ├── README.md ├── fwManager ├── Makefile ├── arm7 │ ├── Makefile │ ├── include │ │ ├── interrupts.h │ │ └── nvram.h │ └── source │ │ ├── interrupts.c │ │ ├── main.c │ │ └── nvram.c └── arm9 │ ├── Makefile │ ├── include │ ├── fileSelector.h │ ├── firmware.h │ └── main.h │ └── source │ ├── fileSelector.c │ └── main.c └── guiTool ├── Makefile ├── include ├── bitstream.h ├── compression.h ├── crc.h ├── firmware.h ├── tree.h └── types.h └── source ├── bitstream.c ├── compression.c ├── crc.c ├── main.c └── tree.c /.gitignore: -------------------------------------------------------------------------------- 1 | guiTool/build 2 | guiTool/*.bin 3 | guiTool/*.bat 4 | guiTool/guiTool 5 | guiTool/guiTool.exe 6 | FlashMeInjector/build 7 | FlashMeInjector/*.bin 8 | FlashMeInjector/*.bat 9 | FlashMeInjector/FlashMeInjector 10 | FlashMeInjector/FlashMeInjector.exe 11 | fwManager/fwManager.nds 12 | fwManager/*.bat 13 | fwManager/arm9/build 14 | fwManager/arm9/fwManager.elf 15 | fwManager/arm7/build 16 | fwManager/arm7/fwManager.elf 17 | -------------------------------------------------------------------------------- /FlashMeInjector/Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | ODIR := build 3 | SDIR := source 4 | IDIR := include 5 | LDIR := lib 6 | CFLAGS := -I$(IDIR) -fms-extensions -O2 -Wall 7 | LFLAGS := -L$(LDIR) 8 | CFILES := $(wildcard $(SDIR)/*.c) 9 | OBJS := $(patsubst $(SDIR)/%.c, build/%.o, $(wildcard $(SDIR)/*.c)) 10 | 11 | PLATFORM = $(shell uname) 12 | 13 | ifeq ($(findstring Linux,$(PLATFORM)),Linux) 14 | TARGET=$(shell basename $(CURDIR)) 15 | endif 16 | 17 | ifeq ($(findstring Darwin,$(PLATFORM)),Darwin) 18 | TARGET=$(shell basename $(CURDIR)) 19 | endif 20 | 21 | ifeq ($(findstring MINGW,$(PLATFORM)),MINGW) 22 | TARGET=$(shell basename $(CURDIR)).exe 23 | endif 24 | 25 | $(TARGET): $(ODIR) $(OBJS) 26 | $(CC) $(ODIR)/*.o -o $(TARGET) $(CFLAGS) $(LFLAGS) 27 | 28 | $(ODIR)/%.o: $(SDIR)/%.c 29 | $(CC) -c -o $@ $< $(CFLAGS) 30 | 31 | $(ODIR): 32 | @mkdir $@ 33 | 34 | .PHONY: clean 35 | 36 | clean: 37 | rm -f $(TARGET) $(ODIR)/*.o 38 | -------------------------------------------------------------------------------- /FlashMeInjector/flashme.nds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTurt/CFW-Suite/f2f2ca1e6a31e7c32edd02682a539a224ec015b7/FlashMeInjector/flashme.nds -------------------------------------------------------------------------------- /FlashMeInjector/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void help(char *name) { 6 | printf("FlashMeInjector - Inject CFW into FlashMe installer\n"); 7 | printf("Usage:\n"); 8 | printf("%s flashme.nds [-lite or -phat] cfw.bin\n", name); 9 | printf(" flashme.nds: filename of FlashMe installer\n"); 10 | printf(" -lite: inject into DS Lite firmware space\n"); 11 | printf(" -phat: inject into original DS firmware space\n"); 12 | printf(" cfw.bin: filename of firmware to inject\n"); 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | enum { 17 | unspecified, 18 | lite, 19 | phat, 20 | } console; 21 | 22 | unsigned int firmwareOffsets[] = { 23 | [lite] = 0x00041234, 24 | [phat] = 0x00001434, 25 | }; 26 | 27 | FILE *f; 28 | 29 | unsigned char *flashme; 30 | unsigned char *cfw; 31 | 32 | size_t flashmeSize; 33 | 34 | unsigned int offset; 35 | 36 | char *flashmeFilename = NULL; 37 | char *cfwFilename = NULL; 38 | 39 | if(argc != 4) { 40 | help(argv[0]); 41 | return 1; 42 | } 43 | 44 | flashmeFilename = argv[1]; 45 | if(strcmp(argv[2], "-lite") == 0) console = lite; 46 | if(strcmp(argv[2], "-phat") == 0) console = phat; 47 | cfwFilename = argv[3]; 48 | 49 | if(console == unspecified) { 50 | help(argv[0]); 51 | return 1; 52 | } 53 | 54 | offset = firmwareOffsets[console]; 55 | 56 | f = fopen(flashmeFilename, "rb"); 57 | fseek(f, 0, SEEK_END); 58 | flashmeSize = ftell(f); 59 | rewind(f); 60 | flashme = malloc(flashmeSize); 61 | fread(flashme, 0x3fe00, 1, f); 62 | fclose(f); 63 | 64 | cfw = malloc(0x3fe00); 65 | f = fopen(cfwFilename, "rb"); 66 | fread(cfw, 0x3fe00, 1, f); 67 | fclose(f); 68 | 69 | //memcpy(flashme + offset, cfw, 0x3fe00); 70 | memset(flashme + offset, 0x00, 0x3fe00); 71 | 72 | f = fopen(flashmeFilename, "wb"); 73 | fwrite(flashme, flashmeSize, 1, f); 74 | fclose(f); 75 | 76 | printf("Injected to 0x%08x\n", offset); 77 | 78 | free(cfw); 79 | free(flashme); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CFW Suite 2 | A collection of tools which can be used to modify some of the text from a DS or DS Lite firmware, to create a custom firmware (CFW). 3 | 4 | See [this video](https://www.youtube.com/watch?v=bF7NuRreoCU) for an example. 5 | 6 | Code from Chism, Loopy, Lick, and others has been used. 7 | 8 | ## Steps to modify the "Touch the Touch Screen to continue." text 9 | ### Dump original firmware 10 | - (Optional but recommended) install a version of [FlashMe](https://home.comcast.net/~olimar/flashme/), this adds a failsafe to your firmware so you can recover if a future flash fails, 11 | - Dump your DS firmware using [DSBF Dump](http://www.ds-scene.net/?s=viewtopic&nid=2460), 12 | 13 | ### Modifying the firmware 14 | - Compile guiTool by running `make`, 15 | - Extract gui data from your firmware with `guiTool firmware.bin -e gui.bin`, 16 | - Make any changes you want to the `gui.bin` file (note: text is Unicode), the "Touch the Touch Screen to continue." text starts at `0x2c20` in the file. 17 | - Make a copy of your firmware (here it is called `cfw.bin`), 18 | - Inject gui data into your custom firmware with `guiTool cfw.bin -i gui.bin`, 19 | - (Optional but recommended) run [DeSmuME](http://desmume.org/), go to `Config->Emulation Settings` and configure it to boot from your custom firmware; this is just to test that it works, 20 | 21 | ### Flashing to hardware (fwManager - recommended method) 22 | - Compile fwManager by running `make`, or download a prebuilt binary, copy it to your flashcard, 23 | - Make a new directory called `firmwares` on your flashcard, 24 | - Place your modified firmware (`cfw.bin`) here, 25 | - Run fwManager and select your custom firmware; when the installer is running, short the SL1 terminal as if you were installing FlashMe. 26 | 27 | ### Flashing to hardware (FlashMeInjector - old method for homebrew loaders that don't support libfat) 28 | - Compile FlashMeInjector by running `make`, 29 | - Inject your firmware into the FlashMe installer with `FlashMeInjector flashme.nds -lite cfw.bin` if you are using a DS Lite, or `FlashMeInjector flashme.nds -phat cfw.bin` if you are using an original DS, 30 | - Run your modified FlashMe installer on your DS, 31 | - FlashMe firmwares have an additional checksum, which will be incorrect, FlashMe will tell you the correct one and won't flash anything, 32 | - Correct the FlashMe checksum with the one your DS told you, and inject the new firmware back into `flashme.nds`, 33 | - Run `flashme.nds` again, from here the installation process will be the same as if you were installing FlashMe normally (SL1 must be shorted), 34 | 35 | If you follow the optional steps, then the risk of a brick will be relatively low; however, I take no responsibility if a brick does happen as a result of using these tools. 36 | 37 | ## Uninstalling 38 | Assuming you kept a backup of your original firmware, you can flash it with fwManager. Alternatively you may use noflashme. 39 | 40 | ### No content owned by Nintendo is contained in this repo! 41 | No firmwares are here, you must dump your own. The firmwares contained in the FlashMe installer have been removed, you must inject your own if you are using FlashMeInjector. -------------------------------------------------------------------------------- /fwManager/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | export TARGET := $(shell basename $(CURDIR)) 11 | export TOPDIR := $(CURDIR) 12 | 13 | 14 | .PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf 15 | 16 | #--------------------------------------------------------------------------------- 17 | # main targets 18 | #--------------------------------------------------------------------------------- 19 | all: $(TARGET).nds 20 | 21 | #--------------------------------------------------------------------------------- 22 | $(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf 23 | ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf 24 | 25 | #--------------------------------------------------------------------------------- 26 | arm7/$(TARGET).elf: 27 | $(MAKE) -C arm7 28 | 29 | #--------------------------------------------------------------------------------- 30 | arm9/$(TARGET).elf: 31 | $(MAKE) -C arm9 32 | 33 | #--------------------------------------------------------------------------------- 34 | clean: 35 | $(MAKE) -C arm9 clean 36 | $(MAKE) -C arm7 clean 37 | rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9 38 | -------------------------------------------------------------------------------- /fwManager/arm7/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include build 20 | DATA := 21 | 22 | #--------------------------------------------------------------------------------- 23 | # options for code generation 24 | #--------------------------------------------------------------------------------- 25 | ARCH := -mthumb-interwork 26 | 27 | CFLAGS := -g -Wall -O2\ 28 | -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ 29 | -ffast-math \ 30 | $(ARCH) 31 | 32 | CFLAGS += $(INCLUDE) -DARM7 33 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti 34 | 35 | 36 | ASFLAGS := -g $(ARCH) 37 | LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map 38 | 39 | LIBS := -ldswifi7 -lmm7 -lnds7 40 | 41 | #--------------------------------------------------------------------------------- 42 | # list of directories containing libraries, this must be the top level containing 43 | # include and lib 44 | #--------------------------------------------------------------------------------- 45 | LIBDIRS := $(LIBNDS) 46 | 47 | 48 | #--------------------------------------------------------------------------------- 49 | # no real need to edit anything past this point unless you need to add additional 50 | # rules for different file extensions 51 | #--------------------------------------------------------------------------------- 52 | ifneq ($(BUILD),$(notdir $(CURDIR))) 53 | #--------------------------------------------------------------------------------- 54 | 55 | export ARM7ELF := $(CURDIR)/$(TARGET).elf 56 | export DEPSDIR := $(CURDIR)/$(BUILD) 57 | 58 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 59 | 60 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 61 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 62 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 63 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 64 | 65 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 66 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 67 | 68 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 69 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 70 | -I$(CURDIR)/$(BUILD) 71 | 72 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 73 | 74 | #--------------------------------------------------------------------------------- 75 | # use CXX for linking C++ projects, CC for standard C 76 | #--------------------------------------------------------------------------------- 77 | ifeq ($(strip $(CPPFILES)),) 78 | #--------------------------------------------------------------------------------- 79 | export LD := $(CC) 80 | #--------------------------------------------------------------------------------- 81 | else 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CXX) 84 | #--------------------------------------------------------------------------------- 85 | endif 86 | #--------------------------------------------------------------------------------- 87 | 88 | .PHONY: $(BUILD) clean 89 | 90 | #--------------------------------------------------------------------------------- 91 | $(BUILD): 92 | @[ -d $@ ] || mkdir -p $@ 93 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 94 | 95 | #--------------------------------------------------------------------------------- 96 | clean: 97 | @echo clean ... 98 | @rm -fr $(BUILD) *.elf 99 | 100 | 101 | #--------------------------------------------------------------------------------- 102 | else 103 | 104 | DEPENDS := $(OFILES:.o=.d) 105 | 106 | #--------------------------------------------------------------------------------- 107 | # main targets 108 | #--------------------------------------------------------------------------------- 109 | $(ARM7ELF) : $(OFILES) 110 | @echo linking $(notdir $@) 111 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 112 | 113 | 114 | #--------------------------------------------------------------------------------- 115 | # you need a rule like this for each extension you use as binary data 116 | #--------------------------------------------------------------------------------- 117 | %.bin.o : %.bin 118 | #--------------------------------------------------------------------------------- 119 | @echo $(notdir $<) 120 | @$(bin2o) 121 | 122 | -include $(DEPENDS) 123 | 124 | #--------------------------------------------------------------------------------------- 125 | endif 126 | #--------------------------------------------------------------------------------------- 127 | -------------------------------------------------------------------------------- /fwManager/arm7/include/interrupts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern volatile unsigned char quit; 4 | 5 | void setInterrupts(void); 6 | -------------------------------------------------------------------------------- /fwManager/arm7/include/nvram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void readFirmware(u32 address, void *destination, u32 size); 6 | int writeFirmwarePage(u32 address, u8 *buffer); 7 | -------------------------------------------------------------------------------- /fwManager/arm7/source/interrupts.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | volatile unsigned char quit = 0; 6 | 7 | static void VblankHandler(void) { 8 | Wifi_Update(); 9 | } 10 | 11 | static void VcountHandler(void) { 12 | inputGetAndSend(); 13 | } 14 | 15 | static void powerButtonCB(void) { 16 | quit = true; 17 | } 18 | 19 | void setInterrupts(void) { 20 | irqSet(IRQ_VCOUNT, VcountHandler); 21 | irqSet(IRQ_VBLANK, VblankHandler); 22 | 23 | irqEnable(IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK); 24 | 25 | setPowerButtonCB(powerButtonCB); 26 | } 27 | -------------------------------------------------------------------------------- /fwManager/arm7/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "interrupts.h" 7 | #include "nvram.h" 8 | 9 | static void wait(void) { 10 | // without any delay at all, it will not flash correctly 11 | // but 5 vblanks may not be necessary 12 | // reduce this number at your own risk 13 | 14 | int i; 15 | for(i = 0; i < 5; i++) swiWaitForVBlank(); 16 | } 17 | 18 | void flash(unsigned char *firmware) { 19 | unsigned int i = 0; 20 | while(i < 0x3f800) { 21 | if(writeFirmwarePage(i, firmware + i)) { 22 | wait(); 23 | } 24 | else { 25 | i += 256; 26 | fifoSendValue32(FIFO_USER_02, i); 27 | wait(); 28 | } 29 | } 30 | } 31 | 32 | int main(void) { 33 | readUserSettings(); 34 | 35 | irqInit(); 36 | initClockIRQ(); 37 | fifoInit(); 38 | 39 | mmInstall(FIFO_MAXMOD); 40 | 41 | SetYtrigger(80); 42 | 43 | installWifiFIFO(); 44 | installSoundFIFO(); 45 | 46 | installSystemFIFO(); 47 | 48 | setInterrupts(); 49 | 50 | while(!quit) { 51 | if(fifoCheckValue32(FIFO_USER_01)) { 52 | unsigned char *firmware = (unsigned char *)fifoGetValue32(FIFO_USER_01); 53 | flash(firmware); 54 | } 55 | 56 | if(fifoCheckValue32(FIFO_USER_03)) { 57 | unsigned int address = fifoGetValue32(FIFO_USER_03); 58 | unsigned char *destination = (unsigned char *)fifoGetValue32(FIFO_USER_03); 59 | size_t length = fifoGetValue32(FIFO_USER_03); 60 | 61 | readFirmware(address, destination, length); 62 | } 63 | 64 | swiIntrWait(1, IRQ_FIFO_NOT_EMPTY | IRQ_VBLANK); 65 | } 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /fwManager/arm7/source/nvram.c: -------------------------------------------------------------------------------- 1 | // This code is from libnds, but for some reason it isn't exposed to us 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "nvram.h" 8 | 9 | static u8 readwriteSPI(u8 data) { 10 | REG_SPIDATA = data; 11 | SerialWaitBusy(); 12 | return REG_SPIDATA; 13 | } 14 | 15 | int writeFirmwarePage(u32 address,u8 *buffer) { 16 | int i; 17 | u8 pagebuffer[256]; 18 | readFirmware(address, pagebuffer, 256); 19 | 20 | if(memcmp(pagebuffer, buffer, 256) == 0) return 0; 21 | 22 | int oldIME = enterCriticalSection(); 23 | 24 | //write enable 25 | REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM; 26 | readwriteSPI(FIRMWARE_WREN); 27 | REG_SPICNT = 0; 28 | 29 | //Wait for Write Enable Latch to be set 30 | REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM; 31 | readwriteSPI(FIRMWARE_RDSR); 32 | while((readwriteSPI(0) & 0x02) == 0); //Write Enable Latch 33 | REG_SPICNT = 0; 34 | 35 | //page write 36 | REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM; 37 | readwriteSPI(FIRMWARE_PW); 38 | // Set the address 39 | readwriteSPI((address>>16) & 0xff); 40 | readwriteSPI((address>> 8) & 0xff); 41 | readwriteSPI((address) & 0xff); 42 | 43 | for(i = 0; i < 256; i++) { 44 | readwriteSPI(buffer[i]); 45 | } 46 | 47 | REG_SPICNT = 0; 48 | 49 | // wait for programming to finish 50 | REG_SPICNT = SPI_ENABLE|SPI_CONTINUOUS|SPI_DEVICE_NVRAM; 51 | readwriteSPI(FIRMWARE_RDSR); 52 | while(readwriteSPI(0) & 0x01); //Write In Progress 53 | REG_SPICNT = 0; 54 | 55 | leaveCriticalSection(oldIME); 56 | 57 | // read it back & verify 58 | readFirmware(address, pagebuffer, 256); 59 | if(memcmp(pagebuffer, buffer, 256) == 0) return 0; 60 | return -1; 61 | } 62 | -------------------------------------------------------------------------------- /fwManager/arm9/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include 20 | DATA := 21 | 22 | 23 | #--------------------------------------------------------------------------------- 24 | # options for code generation 25 | #--------------------------------------------------------------------------------- 26 | ARCH := -mthumb -mthumb-interwork 27 | 28 | CFLAGS := -g -Wall -O2\ 29 | -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ 30 | -ffast-math \ 31 | $(ARCH) 32 | 33 | CFLAGS += $(INCLUDE) -DARM9 34 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 35 | 36 | ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s 37 | 38 | LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 39 | 40 | #--------------------------------------------------------------------------------- 41 | # any extra libraries we wish to link with the project 42 | #--------------------------------------------------------------------------------- 43 | LIBS := -lfat -lnds9 44 | 45 | #--------------------------------------------------------------------------------- 46 | # list of directories containing libraries, this must be the top level containing 47 | # include and lib 48 | #--------------------------------------------------------------------------------- 49 | LIBDIRS := $(LIBNDS) 50 | 51 | #--------------------------------------------------------------------------------- 52 | # no real need to edit anything past this point unless you need to add additional 53 | # rules for different file extensions 54 | #--------------------------------------------------------------------------------- 55 | ifneq ($(BUILD),$(notdir $(CURDIR))) 56 | #--------------------------------------------------------------------------------- 57 | 58 | export ARM9ELF := $(CURDIR)/$(TARGET).elf 59 | export DEPSDIR := $(CURDIR)/$(BUILD) 60 | 61 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 62 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 63 | 64 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 65 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 66 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 67 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 68 | 69 | #--------------------------------------------------------------------------------- 70 | # use CXX for linking C++ projects, CC for standard C 71 | #--------------------------------------------------------------------------------- 72 | ifeq ($(strip $(CPPFILES)),) 73 | #--------------------------------------------------------------------------------- 74 | export LD := $(CC) 75 | #--------------------------------------------------------------------------------- 76 | else 77 | #--------------------------------------------------------------------------------- 78 | export LD := $(CXX) 79 | #--------------------------------------------------------------------------------- 80 | endif 81 | #--------------------------------------------------------------------------------- 82 | 83 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 84 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 85 | 86 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 87 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 88 | -I$(CURDIR)/$(BUILD) 89 | 90 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 91 | 92 | .PHONY: $(BUILD) clean 93 | 94 | #--------------------------------------------------------------------------------- 95 | $(BUILD): 96 | @[ -d $@ ] || mkdir -p $@ 97 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 98 | 99 | #--------------------------------------------------------------------------------- 100 | clean: 101 | @echo clean ... 102 | @rm -fr $(BUILD) *.elf *.nds* *.bin 103 | 104 | 105 | #--------------------------------------------------------------------------------- 106 | else 107 | 108 | #--------------------------------------------------------------------------------- 109 | # main targets 110 | #--------------------------------------------------------------------------------- 111 | $(ARM9ELF) : $(OFILES) 112 | @echo linking $(notdir $@) 113 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 114 | 115 | #--------------------------------------------------------------------------------- 116 | # you need a rule like this for each extension you use as binary data 117 | #--------------------------------------------------------------------------------- 118 | %.bin.o : %.bin 119 | #--------------------------------------------------------------------------------- 120 | @echo $(notdir $<) 121 | @$(bin2o) 122 | 123 | -include $(DEPSDIR)/*.d 124 | 125 | #--------------------------------------------------------------------------------------- 126 | endif 127 | #--------------------------------------------------------------------------------------- 128 | -------------------------------------------------------------------------------- /fwManager/arm9/include/fileSelector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char *selectFirmware(void); 4 | -------------------------------------------------------------------------------- /fwManager/arm9/include/firmware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct header { 6 | u16 part3offset; 7 | u16 part4offset; 8 | u16 part34crc; 9 | u16 part12crc; 10 | u8 identifier[4]; 11 | u16 part1offset; 12 | u16 part1ramAddress; 13 | u16 part2offset; 14 | u16 part2ramAddress; 15 | u16 shift; 16 | u16 part5offset; 17 | 18 | u8 timestamp[5]; 19 | u8 console; 20 | u16 unused1; 21 | u16 userSettingsOffset; 22 | u16 unknown1; // crc 23 | u16 unknown2; 24 | u16 part5crc; 25 | u16 unused2; 26 | }; 27 | -------------------------------------------------------------------------------- /fwManager/arm9/include/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern PrintConsole *console; -------------------------------------------------------------------------------- /fwManager/arm9/source/fileSelector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "main.h" 7 | 8 | #include "fileSelector.h" 9 | 10 | static char filenames[5][256]; 11 | static char fullPath[512]; 12 | 13 | char *selectFirmware(void) { 14 | DIR *pdir; 15 | struct dirent *pent; 16 | 17 | int fileCount = 0; 18 | int selection = 0; 19 | 20 | pdir = opendir("/firmwares"); 21 | 22 | printf(" Select firmware image to flash:\n"); 23 | 24 | if(pdir) { 25 | while((pent = readdir(pdir)) != NULL && fileCount < 5) { 26 | if(strcmp(".", pent->d_name) == 0 || strcmp("..", pent->d_name) == 0) continue; 27 | if(pent->d_type == DT_DIR) continue; 28 | 29 | strncpy(filenames[fileCount], pent->d_name, 255); 30 | fileCount++; 31 | } 32 | 33 | closedir(pdir); 34 | 35 | while(1) { 36 | scanKeys(); 37 | 38 | console->cursorY = 10; 39 | 40 | int i; 41 | for(i = 0; i < fileCount; i++) { 42 | if(i == selection) printf("*"); 43 | else printf(" "); 44 | 45 | printf("%s\n", filenames[i]); 46 | } 47 | 48 | if(keysDown() & KEY_DOWN && selection < fileCount - 1) selection++; 49 | if(keysDown() & KEY_UP && selection > 0) selection--; 50 | 51 | if(keysDown() & KEY_A) { 52 | sprintf(fullPath, "/firmwares/%s", filenames[selection]); 53 | return fullPath; 54 | } 55 | 56 | swiWaitForVBlank(); 57 | } 58 | } 59 | else { 60 | printf(" \"/firmwares\" not found!\n"); 61 | return NULL; 62 | } 63 | } -------------------------------------------------------------------------------- /fwManager/arm9/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "firmware.h" 7 | #include "fileSelector.h" 8 | 9 | #include "main.h" 10 | 11 | PrintConsole *console; 12 | 13 | static unsigned char flashing = 0; 14 | 15 | void firmwareRead(unsigned int address, unsigned char *destination, size_t length) { 16 | fifoSendValue32(FIFO_USER_03, address); 17 | fifoSendValue32(FIFO_USER_03, (u32)destination); 18 | fifoSendValue32(FIFO_USER_03, length); 19 | } 20 | 21 | void startFlash(unsigned char *firmware) { 22 | consoleClear(); 23 | printf("\n Flashing firmware!\n\n Keep SL1 terminal shorted to\n progress.\n"); 24 | flashing = 1; 25 | fifoSendValue32(FIFO_USER_01, (u32)firmware); 26 | } 27 | 28 | int main(void) { 29 | console = consoleDemoInit(); 30 | 31 | printf("\n fwManager - CTurt\n"); 32 | printf(" =================\n\n"); 33 | 34 | /*if(REG_DSIMODE) { 35 | printf(" Cannot use on DSi/3DS!\n"); 36 | while(1) swiWaitForVBlank(); 37 | }*/ //let's be honest, we all know this is for fat DSes and lites, this check only gives me errors when compiling the soft 38 | 39 | printf(" Warning!\n This tool may damage your\n system! Use at your own risk!\n\n"); 40 | 41 | if(!fatInitDefault()) { 42 | printf(" Could not init FAT!\n"); 43 | } 44 | 45 | char *firmwareFilename = selectFirmware(); 46 | 47 | if(!firmwareFilename) { 48 | while(1) swiWaitForVBlank(); 49 | } 50 | 51 | consoleClear(); 52 | 53 | printf("\n Press Start to flash:\n\n %s\n\n", firmwareFilename); 54 | 55 | do { 56 | scanKeys(); 57 | swiWaitForVBlank(); 58 | } while(keysHeld() & KEY_START); 59 | 60 | do { 61 | scanKeys(); 62 | swiWaitForVBlank(); 63 | } while(!(keysHeld() & KEY_START)); 64 | 65 | do { 66 | scanKeys(); 67 | swiWaitForVBlank(); 68 | } while(keysHeld() & KEY_START); 69 | 70 | FILE *f = fopen(firmwareFilename, "rb"); 71 | if(!f) { 72 | printf(" Could not open file!\n"); 73 | while(1) swiWaitForVBlank(); 74 | } 75 | 76 | fseek(f, 0, SEEK_END); 77 | size_t size = ftell(f); 78 | if(size < 0x3fe00) { 79 | printf(" Firmware is too small!\n"); 80 | while(1) swiWaitForVBlank(); 81 | } 82 | 83 | unsigned char *firmware = malloc(size); 84 | if(!firmware) { 85 | printf(" Malloc failed!\n"); 86 | while(1) swiWaitForVBlank(); 87 | } 88 | 89 | rewind(f); 90 | fread(firmware, size, 1, f); 91 | fclose(f); 92 | 93 | // To do: check console is compatible 94 | /* 95 | unsigned char system = readPM(4); 96 | if(system != ((struct header *)firmware)->console) { 97 | printf(" This firmware is not for this console!\n"); 98 | printf(" This console is type %d (%s)\n firmware is for type %d (%s)\n", system, system & 0x40 == 0x40 ? "lite" : "phat", ((struct header *)firmware)->console, ((struct header *)firmware)->console & 0x40 == 0x40 ? "lite" : "phat"); 99 | while(1) swiWaitForVBlank(); 100 | } 101 | */ 102 | 103 | // To do: check boot CRC is correct 104 | /* 105 | unsigned short crc; 106 | // decrypt and decompress arm 7 and 9 binaries 107 | crc = swiCRC16(0xffff, part1, part1size); 108 | crc = swiCRC16(crc, part2, part2size); 109 | if(((struct header *)firmware)->part12crc != crc) { 110 | printf(" Incorrect boot CRC!\n"); 111 | while(1) swiWaitForVBlank(); 112 | } 113 | */ 114 | 115 | unsigned char *originalFirmware = malloc(0x40000); 116 | firmwareRead(0, originalFirmware, 0x40000); 117 | 118 | unsigned short crc = *(u16 *)(originalFirmware + 0x17e); 119 | if(crc == 0xffff) crc = *(u16 *)(originalFirmware + 6); 120 | /* 121 | int i; 122 | for(i = 0; i < (0x170 - 0x28); i++) { 123 | firmware[i + 0x28] = firmware[i + 0x3f680 + 0x28] = originalFirmware[i + 0x28]; 124 | } 125 | 126 | *(u16 *)(firmware + 0x17e) = *(u16 *)(firmware + 0x3f680 + 0x17e) = crc; 127 | 128 | free(originalFirmware); 129 | */ //strangely fixes wi-fi 130 | startFlash(firmware); 131 | 132 | while(1) { 133 | if(flashing) { 134 | if(fifoCheckValue32(FIFO_USER_02)) { 135 | unsigned int progress = fifoGetValue32(FIFO_USER_02); 136 | 137 | console->cursorX = 1; 138 | console->cursorY = 6; 139 | printf("Progress: %d%%", (int)((double)progress / 0x3f800 * 100)); 140 | //printf("Progress: %d / %d", progress, 0x3f800); 141 | 142 | if(progress == 0x3f800) { 143 | printf("\n\n Done!\n"); 144 | flashing = 0; 145 | } 146 | } 147 | } 148 | 149 | swiWaitForVBlank(); 150 | scanKeys(); 151 | } 152 | 153 | free(firmware); 154 | 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /guiTool/Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | ODIR := build 3 | SDIR := source 4 | IDIR := include 5 | LDIR := lib 6 | CFLAGS := -I$(IDIR) -fms-extensions -O2 -Wall 7 | LFLAGS := -L$(LDIR) 8 | CFILES := $(wildcard $(SDIR)/*.c) 9 | OBJS := $(patsubst $(SDIR)/%.c, build/%.o, $(wildcard $(SDIR)/*.c)) 10 | 11 | PLATFORM = $(shell uname) 12 | 13 | ifeq ($(findstring Linux,$(PLATFORM)),Linux) 14 | TARGET=$(shell basename $(CURDIR)) 15 | endif 16 | 17 | ifeq ($(findstring Darwin,$(PLATFORM)),Darwin) 18 | TARGET=$(shell basename $(CURDIR)) 19 | endif 20 | 21 | ifeq ($(findstring MINGW,$(PLATFORM)),MINGW) 22 | TARGET=$(shell basename $(CURDIR)).exe 23 | endif 24 | 25 | $(TARGET): $(ODIR) $(OBJS) 26 | $(CC) $(ODIR)/*.o -o $(TARGET) $(CFLAGS) $(LFLAGS) 27 | 28 | $(ODIR)/%.o: $(SDIR)/%.c 29 | $(CC) -c -o $@ $< $(CFLAGS) 30 | 31 | $(ODIR): 32 | @mkdir $@ 33 | 34 | .PHONY: clean 35 | 36 | clean: 37 | rm -f $(TARGET) $(ODIR)/*.o 38 | -------------------------------------------------------------------------------- /guiTool/include/bitstream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef struct _BITSTREAM BITSTREAM; 6 | 7 | struct _BITSTREAM { 8 | u8 *ptr; 9 | u8 bit; 10 | u8 byte; 11 | u32 pos; 12 | }; 13 | 14 | void bitstream_clear(BITSTREAM *bs); 15 | void bitstream_write(BITSTREAM *bs, u32 size, u32 data); 16 | u32 bitstream_read(BITSTREAM *bs, u32 size); 17 | u32 bitstream_peek(BITSTREAM *bs, u32 size); 18 | -------------------------------------------------------------------------------- /guiTool/include/compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | // level 6 | // 0 = store 7 | // 1 = compress 8 | // 2 = compress + optimise 9 | struct _ARGS_VPK_COMPRESS { 10 | char filelog[256]; 11 | u8 level; 12 | u8 method; 13 | u32 lz_move_max; 14 | }; 15 | 16 | struct _ARGS_VPK_DECOMPRESS { 17 | char filelog[256]; 18 | }; 19 | 20 | typedef struct _ARGS_VPK_COMPRESS ARGS_VPK_COMPRESS; 21 | typedef struct _ARGS_VPK_DECOMPRESS ARGS_VPK_DECOMPRESS; 22 | 23 | u32 decompress(u8 *dst, u8 *src); 24 | u32 compress(u8 *dst, u8 *src, u32 size); 25 | -------------------------------------------------------------------------------- /guiTool/include/crc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | u16 swiCRC(u16 crc, u32 *r2, u32 r0); 6 | -------------------------------------------------------------------------------- /guiTool/include/firmware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | struct header { 6 | u16 part3offset; 7 | u16 part4offset; 8 | u16 part34crc; 9 | u16 part12crc; 10 | u8 identifier[4]; 11 | u16 part1offset; 12 | u16 part1ramAddress; 13 | u16 part2offset; 14 | u16 part2ramAddress; 15 | u16 shift; 16 | u16 part5offset; 17 | 18 | u8 timestamp[5]; 19 | u8 console; 20 | u16 unused1; 21 | u16 userSettingsOffset; 22 | u16 unknown1; 23 | u16 unknown2; 24 | u16 part5crc; 25 | u16 unused2; 26 | }; 27 | -------------------------------------------------------------------------------- /guiTool/include/tree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef struct _NODE NODE, *PNODE; 6 | 7 | typedef struct _NODE { 8 | PNODE left; 9 | PNODE right; 10 | u32 value; 11 | u32 weight; 12 | } NODE, *PNODE; 13 | 14 | NODE* node_create(NODE *left, NODE *right, u32 value, u32 weight); 15 | void free_tree(NODE *node); 16 | -------------------------------------------------------------------------------- /guiTool/include/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef unsigned char u8; 6 | typedef unsigned short u16; 7 | typedef unsigned long u32; 8 | typedef unsigned __int64 u64; 9 | 10 | typedef signed char s8; 11 | typedef signed short s16; 12 | typedef signed long s32; 13 | typedef __int64 s64; 14 | 15 | typedef unsigned char bool; 16 | 17 | #define false 0 18 | #define true 1 19 | -------------------------------------------------------------------------------- /guiTool/source/bitstream.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "bitstream.h" 5 | 6 | void bitstream_clear(BITSTREAM *bs) { 7 | memset(bs, 0, sizeof(BITSTREAM)); 8 | } 9 | 10 | void bitstream_write(BITSTREAM *bs, u32 size, u32 data) { 11 | u32 i; 12 | 13 | for(i = 0; i < size; i++) { 14 | bs->byte = (u8)((bs->byte << 1) | ((data >> (size - 1 - i)) & 1)); 15 | bs->bit++; 16 | if(bs->bit == 8) { 17 | *(bs->ptr + bs->pos) = bs->byte; 18 | bs->pos++; 19 | bs->bit = 0; 20 | } 21 | } 22 | } 23 | 24 | u32 bitstream_read(BITSTREAM *bs, u32 size) { 25 | u32 i, result = 0; 26 | 27 | for(i = 0; i < size; i++) { 28 | if(bs->bit == 0) { 29 | bs->byte = *(bs->ptr + bs->pos); 30 | bs->pos++; 31 | bs->bit = 8; 32 | } 33 | 34 | bs->bit--; 35 | result = (result << 1) | ((bs->byte >> bs->bit) & 1); 36 | } 37 | 38 | return result; 39 | } 40 | 41 | u32 bitstream_peek(BITSTREAM *bs, u32 size) { 42 | u32 value; 43 | BITSTREAM save; 44 | 45 | save = *bs; 46 | value = bitstream_read( bs, size); 47 | *bs = save; 48 | return value; 49 | } 50 | -------------------------------------------------------------------------------- /guiTool/source/compression.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "compression.h" 6 | 7 | #include "bitstream.h" 8 | #include "tree.h" 9 | 10 | #define LZ_SIZE_MIN 3 11 | #define LZ_SIZE_MAX 255 12 | 13 | typedef struct _DPV_TABLE { 14 | u32 depth; 15 | u32 path; 16 | u32 value; 17 | } DPV_TABLE, *PDPV_TABLE; 18 | 19 | static void vpk_tree_save(PNODE node, BITSTREAM *bs, u32 bitlen); 20 | 21 | static void vpk_tree_save(PNODE node, BITSTREAM *bs, u32 bitlen) { 22 | if(node) { 23 | if((node->left) || (node->right)) { 24 | bitstream_write(bs, 1, 1); 25 | if(node->left) vpk_tree_save(node->left, bs, bitlen); 26 | if(node->right) vpk_tree_save(node->right, bs, bitlen); 27 | } 28 | else { 29 | bitstream_write(bs, 1, 0); 30 | bitstream_write(bs, bitlen, node->value); 31 | } 32 | } 33 | } 34 | 35 | static PNODE build_tree_from_freq_table(u32 *freq, u32 items) { 36 | u32 i, weight, index, bits; 37 | PNODE nodes[0x800+0x1000], tree, node1, node2, node; 38 | 39 | (void)bits; 40 | 41 | // init 42 | memset(&nodes[0], 0, sizeof(nodes)); 43 | tree = NULL; 44 | bits = 0; 45 | 46 | // create nodes 47 | for(i = 0; i < items; i++) { 48 | weight = freq[i]; 49 | if(weight != 0) nodes[i] = node_create(NULL, NULL, i, weight); 50 | } 51 | 52 | // build tree 53 | index = items; 54 | while(1) { 55 | // find 2 nodes with the smallest weight 56 | node1 = NULL; 57 | node2 = NULL; 58 | for(i = 0; i < index; i++) { 59 | node = nodes[i]; 60 | if((!node) || (node->weight == 0)) continue; 61 | if(!node1) { 62 | node1 = node; 63 | } 64 | else { 65 | if(!node2) { 66 | node2 = node; 67 | } 68 | else { 69 | if((node->weight < node1->weight) || (node->weight < node2->weight)) { 70 | if(node1->weight > node2->weight) node1 = node; else node2 = node; 71 | } 72 | } 73 | } 74 | } 75 | 76 | if((node1) && (node2)) { 77 | // create parent node 78 | nodes[index++] = node_create(node1, node2, 0, node1->weight + node2->weight); 79 | node1->weight = 0; 80 | node2->weight = 0; 81 | } 82 | else { 83 | // get root node 84 | if(node1 != NULL) tree = node1; else tree = node2; 85 | break; 86 | } 87 | } 88 | 89 | return tree; 90 | } 91 | 92 | static void tree_get_depth_and_path_for_value( PNODE node, u32 value, u32 depth, u32 path, int *depthx, int *pathx) { 93 | if(node) { 94 | if((node->left) || (node->right)) { 95 | if(node->left) tree_get_depth_and_path_for_value( node->left, value, depth+1, (path<<1)+0, depthx, pathx); 96 | if(node->right) tree_get_depth_and_path_for_value( node->right, value, depth+1, (path<<1)+1, depthx, pathx); 97 | } 98 | else { 99 | if(node->value == value) { 100 | *depthx = depth; 101 | *pathx = path; 102 | } 103 | } 104 | } 105 | } 106 | 107 | static void tree_to_dpv(PNODE node, DPV_TABLE* dpv, u32 items, bool ereader) { 108 | u32 last; 109 | int depth, path, i; 110 | 111 | last = 0; 112 | memset(dpv, 0, sizeof(DPV_TABLE) * items); 113 | for(i = items - 1; i >= 0; i--) { 114 | if((ereader) && (i == 0)) continue; 115 | depth = -1; 116 | path = -1; 117 | tree_get_depth_and_path_for_value(node, i, 0, 0, &depth, &path); 118 | if(depth != -1) { 119 | dpv[i].depth = depth; 120 | dpv[i].path = path; 121 | dpv[i].value = i; 122 | last = i; 123 | } 124 | else { 125 | if(ereader) { 126 | dpv[i].depth = dpv[last].depth; 127 | dpv[i].path = dpv[last].path; 128 | dpv[i].value = dpv[last].value; 129 | } 130 | } 131 | } 132 | } 133 | 134 | typedef struct _DATA_DEC { 135 | u16 unk1; 136 | u32 value; 137 | u32 unk2; 138 | u32 *table[2]; 139 | u8 bitlen; 140 | BITSTREAM bitstream; 141 | } DATA_DEC, *PDATA_DEC; 142 | 143 | DATA_DEC datadec[2]; 144 | 145 | static u32 stream_read_bits(u32 bits, u32 sel) { 146 | return bitstream_read(&datadec[sel].bitstream, bits); 147 | } 148 | 149 | static u32 make_tree(u8 *src, u32 sel) { 150 | u32 r0, r2, pos; 151 | u16 temp[256], r8, r9; 152 | 153 | r8 = r9 = datadec[sel].unk1; 154 | pos = 0; 155 | 156 | loc_23285B4: 157 | r0 = stream_read_bits(1, sel); 158 | if(r0 != 0) { 159 | temp[pos++] = r9 | 0x8000; 160 | temp[pos++] = r9 | 0x4000; 161 | r9++; 162 | r8++; 163 | goto loc_23285B4; 164 | } 165 | 166 | r0 = stream_read_bits( datadec[sel].bitlen, sel); 167 | do { 168 | pos--; 169 | r2 = temp[pos]; 170 | if(r2 & 0x8000) { 171 | r2 = r2 & 0x3FFF; 172 | *(datadec[sel].table[1] + r2) = r0; 173 | r0 = r2; 174 | } 175 | else { 176 | r2 = r2 & 0x3FFF; 177 | *(datadec[sel].table[0] + r2) = r0; 178 | r9 = r8; 179 | goto loc_23285B4; 180 | } 181 | } while(pos != 0); 182 | 183 | datadec[sel].unk2 = r0; 184 | 185 | return r0; 186 | } 187 | 188 | u32 decompress(u8 *dst, u8 *src) { 189 | u32 r0, pos, x1, x2, sizedec, posdst, len, offset; 190 | 191 | // decompressed size 192 | sizedec = (src[5] << 16) | (src[6] << 8) | (src[7] << 0); 193 | if(!dst) return sizedec; 194 | 195 | // init 1st stream (contains lz single bytes or lz lengths) 196 | bitstream_clear(&datadec[0].bitstream); 197 | offset = 12; 198 | datadec[0].bitstream.ptr = src + offset; 199 | datadec[0].unk1 = 0x200; 200 | datadec[0].value = 0; 201 | datadec[0].bitlen = 9; 202 | datadec[0].table[0] = malloc(0x1000); 203 | datadec[0].table[1] = malloc(0x1000); 204 | make_tree(src, 0); 205 | 206 | // init 2nd stream (contains lz distance values) 207 | bitstream_clear(&datadec[1].bitstream); 208 | offset = (src[8] << 24) | (src[9] << 16) | (src[10] << 8) | (src[11] << 0); 209 | datadec[1].bitstream.ptr = src + offset; 210 | datadec[1].unk1 = 0x800; 211 | datadec[1].value = 0; 212 | datadec[1].bitlen = 11; 213 | datadec[1].table[0] = malloc(0x4000); 214 | datadec[1].table[1] = malloc(0x4000); 215 | make_tree(src, 1); 216 | 217 | r0 = sizedec; 218 | posdst = 0; 219 | while(posdst < sizedec) { 220 | x1 = datadec[0].unk2; 221 | while(x1 >= 0x200) { 222 | r0 = stream_read_bits(1, 0); 223 | x1 = *(datadec[0].table[r0] + x1); 224 | } 225 | if(x1 < 0x100) { 226 | dst[posdst++] = (u8)x1; 227 | } 228 | else { 229 | x2 = datadec[1].unk2; 230 | while(x2 >= 0x800) { 231 | r0 = stream_read_bits(1, 1); 232 | x2 = *(datadec[1].table[r0] + x2); 233 | } 234 | 235 | pos = posdst - x2 - 1; 236 | len = x1 - 0x100 + 3; 237 | while(len--) { 238 | dst[posdst++] = dst[pos++]; 239 | } 240 | } 241 | } 242 | 243 | // cleanup 244 | free(datadec[0].table[0]); 245 | free(datadec[0].table[1]); 246 | free(datadec[1].table[0]); 247 | free(datadec[1].table[1]); 248 | 249 | return posdst; 250 | } 251 | 252 | static u32 lz_memcmp(u8 *mem1, u8 *mem2, u32 max) { 253 | u32 ret; 254 | ret = 0; 255 | while((*mem1++ == *mem2++) && (max-- > 0)) ret++; 256 | return ret; 257 | } 258 | 259 | static void lz_search(u8 *src, u32 pos, u32 srcmax, u32 *back, u32 *length) { 260 | u32 i, len; 261 | 262 | // init 263 | *back = 0; 264 | *length = 0; 265 | 266 | for(i = 0; i < 0x800; i++) { 267 | if(i < pos) { 268 | len = lz_memcmp(src + pos, src + pos - i - 1, srcmax - pos); 269 | if((len > 2) && (len > *length)) { 270 | *length = len; 271 | *back = i + 1; 272 | } 273 | } 274 | } 275 | } 276 | 277 | static u32 swap32(u32 value) { 278 | u8 src[4], dst[4]; 279 | memcpy(src, &value, 4); 280 | dst[0] = src[3]; 281 | dst[1] = src[2]; 282 | dst[2] = src[1]; 283 | dst[3] = src[0]; 284 | return dst[0] | dst[1] << 8 | dst[2] << 16 | dst[3] << 24; 285 | } 286 | 287 | u32 compress(u8 *dst, u8 *src, u32 size) { 288 | u32 i, back, length; 289 | u32 *freq[2]; 290 | PNODE tree[2]; 291 | PDPV_TABLE dpv[2]; 292 | BITSTREAM bs[2], bsdst; 293 | u32 bitlen[2], ret; 294 | 295 | bitlen[0] = 9; 296 | bitlen[1] = 11; 297 | 298 | // init bitstream 299 | for(i = 0; i < 2; i++) { 300 | bitstream_clear(&bs[i]); 301 | bs[i].ptr = malloc(256 * 1024); 302 | } 303 | 304 | // alloc freq table 305 | for(i = 0; i < 2; i++) { 306 | freq[i] = malloc((1 << bitlen[i]) * 4); 307 | memset(freq[i], 0, (1 << bitlen[i]) * 4); 308 | } 309 | 310 | // alloc depth-to-value table 311 | for(i = 0; i < 2; i++) { 312 | dpv[i] = malloc(sizeof(DPV_TABLE) * (1 << bitlen[i])); 313 | } 314 | 315 | // lz compress (part 1) 316 | i = 0; 317 | while(i < size) { 318 | lz_search(src, i, size, &back, &length); 319 | if(back != 0) { 320 | if(length > 0x102) length = 0x102; 321 | *(freq[1] + back - 1) += 1; 322 | *(freq[0] + length - 3 + 0x100) += 1; 323 | //printf("(b) lz - pos1=%08X pos2=%08X len=%08X back=%08X\n", i - back, i, length, back); 324 | i += length; 325 | } 326 | else { 327 | *(freq[0] + src[i]) += 1; 328 | //printf("(b) lz - %02X\n", *(data + i)); 329 | i++; 330 | } 331 | } 332 | 333 | // tree 334 | for(i = 0; i < 2; i++) { 335 | //printf("freq1\n"); for(i = 0; i < 0x200; i++) printf("%04X = %d\n", i, freq1[i]); 336 | tree[i] = build_tree_from_freq_table(freq[i], (1 << bitlen[i])); 337 | //printf("tree 1\n"); tree_fprint(stdout, tree[0]); printf("\r\n"); 338 | tree_to_dpv(tree[i], dpv[i], (1 << bitlen[i]), false); 339 | //printf("dpv1\n"); for (i=0;i<(u32)(1 << bitlen[i]);i++) printf("%08X - depth=%08X path=%08X value=%08X\n", i, dpv[i]->depth, dpv[i]->path, dpv[i]->value); 340 | vpk_tree_save(tree[i], &bs[i], bitlen[i]); 341 | free_tree(tree[i]); 342 | } 343 | 344 | // lz compress (part 2) 345 | i = 0; 346 | while(i < size) { 347 | lz_search(src, i, size, &back, &length); 348 | if(back != 0) { 349 | if(length > 0x102) length = 0x102; 350 | bitstream_write(&bs[1], (dpv[1] + back - 1)->depth, (dpv[1] + back - 1)->path); 351 | bitstream_write(&bs[0], (dpv[0] + length - 3 + 0x100)->depth, (dpv[0] + length - 3 + 0x100)->path); 352 | //printf("(b) lz - pos1=%08X pos2=%08X len=%08X back=%08X\n", i - back, i, length, back); 353 | i += length; 354 | } 355 | else { 356 | bitstream_write(&bs[0], (dpv[0] + src[i])->depth, (dpv[0] + src[i])->path); 357 | //printf("(b) lz - %02X\n", *(data + i)); 358 | i++; 359 | } 360 | } 361 | 362 | // finish bitstream (multiple of 4 byte) 363 | for(i = 0; i < 2; i++) { 364 | while(((bs[i].pos % 4) != 0) || (bs[i].bit != 0)) bitstream_write(&bs[i], 1, 0); 365 | } 366 | 367 | // combine data 368 | ret = 12 + bs[0].pos + bs[1].pos; 369 | memset(dst, 0, ret); 370 | bitstream_clear(&bsdst); 371 | bsdst.ptr = dst; 372 | bitstream_write(&bsdst, 8 * 3, swap32(ret * 4) >> 8); 373 | bitstream_write(&bsdst, 8 * 1, 0x80); 374 | bitstream_write(&bsdst, 8 * 1, 0x80); 375 | bitstream_write(&bsdst, 8 * 3, size); 376 | bitstream_write(&bsdst, 8 * 4, 12 + bs[0].pos); 377 | memcpy(dst + 12, bs[0].ptr, bs[0].pos); 378 | memcpy(dst + 12 + bs[0].pos, bs[1].ptr, bs[1].pos); 379 | // free depth-to-value table 380 | for(i = 0; i < 2; i++) free(dpv[i]); 381 | // free freq table 382 | for(i = 0; i < 2; i++) free(freq[i]); 383 | // free bitstream data 384 | for(i = 0; i < 2; i++) free(bs[i].ptr); 385 | 386 | return ret; 387 | } 388 | -------------------------------------------------------------------------------- /guiTool/source/crc.c: -------------------------------------------------------------------------------- 1 | #include "crc.h" 2 | 3 | static const unsigned short crc16tab[] = { 4 | 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 5 | 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 6 | 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 7 | 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 8 | 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 9 | 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 10 | 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 11 | 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 12 | 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 13 | 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 14 | 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 15 | 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 16 | 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 17 | 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 18 | 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 19 | 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 20 | 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 21 | 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 22 | 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 23 | 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 24 | 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 25 | 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 26 | 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 27 | 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 28 | 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 29 | 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 30 | 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 31 | 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 32 | 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 33 | 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 34 | 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 35 | 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 36 | }; 37 | 38 | u16 swiCRC(u16 crc, u32 *r2, u32 r0) { 39 | u32 i; 40 | 41 | for(i = 0; i < r0; i++) { 42 | u8 data = *((unsigned char *)r2 + i); 43 | crc = (crc >> 8) ^ crc16tab[(crc ^ data) & 0xff]; 44 | } 45 | 46 | return crc; 47 | } 48 | -------------------------------------------------------------------------------- /guiTool/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "firmware.h" 6 | #include "compression.h" 7 | #include "crc.h" 8 | 9 | static void help(char *name) { 10 | printf("DS firmware GUI data extractor and injector\n"); 11 | printf("Usage:\n"); 12 | printf("%s firmware.bin [-e or -i] gui.bin\n", name); 13 | printf(" firmware.bin: filename of firmware\n"); 14 | printf(" -e: extract gui data\n"); 15 | printf(" -i: inject gui data\n"); 16 | printf(" gui.bin: output or input of gui data\n"); 17 | } 18 | 19 | int main(int argc, char **argv) { 20 | enum { 21 | unspecified, 22 | extract, 23 | inject, 24 | } mode; 25 | 26 | unsigned char *firmware; 27 | 28 | char *firmwareFilename = NULL; 29 | char *guiFilename = NULL; 30 | 31 | if(argc != 4) { 32 | help(argv[0]); 33 | return 1; 34 | } 35 | 36 | firmwareFilename = argv[1]; 37 | if(strcmp(argv[2], "-e") == 0) mode = extract; 38 | if(strcmp(argv[2], "-i") == 0) mode = inject; 39 | guiFilename = argv[3]; 40 | 41 | if(mode == unspecified) { 42 | help(argv[0]); 43 | return 1; 44 | } 45 | 46 | FILE *f = fopen(firmwareFilename, "rb"); 47 | fseek(f, 0, SEEK_END); 48 | size_t size = ftell(f); 49 | rewind(f); 50 | firmware = malloc(size); 51 | fread(firmware, size, 1, f); 52 | fclose(f); 53 | 54 | if(mode == extract) { 55 | unsigned int guiOffset; 56 | unsigned char *guiData; 57 | size_t guiSize; 58 | 59 | guiOffset = ((struct header *)firmware)->part5offset * 8; 60 | guiSize = decompress(NULL, firmware + guiOffset); 61 | guiData = malloc(guiSize); 62 | decompress(guiData, firmware + guiOffset); 63 | 64 | f = fopen(guiFilename, "wb"); 65 | fwrite(guiData, guiSize, 1, f); 66 | fclose(f); 67 | 68 | printf("Decompressed gui data from %08x, size %d\n", guiOffset, guiSize); 69 | 70 | free(guiData); 71 | } 72 | 73 | else { 74 | unsigned char *gui, *compressed; 75 | size_t guiSize, compressedSize; 76 | 77 | unsigned char *firmware; 78 | unsigned int guiOffset; 79 | 80 | FILE *f = fopen(guiFilename, "rb"); 81 | fseek(f, 0, SEEK_END); 82 | guiSize = ftell(f); 83 | rewind(f); 84 | gui = malloc(guiSize); 85 | fread(gui, guiSize, 1, f); 86 | fclose(f); 87 | 88 | compressed = malloc(256 * 1024); 89 | compressedSize = compress(compressed, gui, guiSize); 90 | 91 | printf("Compressed gui data to size %d\n", compressedSize); 92 | 93 | f = fopen(firmwareFilename, "rb"); 94 | fseek(f, 0, SEEK_END); 95 | size_t size = ftell(f); 96 | rewind(f); 97 | firmware = malloc(size); 98 | fread(firmware, size, 1, f); 99 | fclose(f); 100 | 101 | guiOffset = ((struct header *)firmware)->part5offset * 8; 102 | 103 | // GUI data is not the final section, after it comes apps like pictochat 104 | /*if(guiOffset + compressedSize > size) { 105 | printf("ERROR! Not enough space for compressed gui data!\n"); 106 | free(firmware); 107 | free(compressed); 108 | free(gui); 109 | return 1; 110 | } 111 | 112 | memset(firmware + guiOffset, 0xff, 0x0003fa00 - guiOffset); 113 | */ 114 | 115 | memcpy(firmware + guiOffset, compressed, compressedSize); 116 | 117 | ((struct header *)firmware)->part5crc = swiCRC(0xffff, (u32 *)(firmware + guiOffset), compressedSize); 118 | 119 | f = fopen(firmwareFilename, "wb"); 120 | fwrite(firmware, size, 1, f); 121 | fclose(f); 122 | 123 | free(compressed); 124 | free(gui); 125 | } 126 | 127 | free(firmware); 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /guiTool/source/tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tree.h" 4 | 5 | PNODE node_create(PNODE left, PNODE right, u32 value, u32 weight) { 6 | PNODE node; 7 | node = (PNODE)malloc( sizeof( NODE)); 8 | node->left = left; 9 | node->right = right; 10 | node->value = value; 11 | node->weight = weight; 12 | return node; 13 | } 14 | 15 | void free_tree(PNODE node) { 16 | if(node) { 17 | free_tree(node->left); 18 | free_tree(node->right); 19 | free(node); 20 | } 21 | } 22 | --------------------------------------------------------------------------------