diff --git a/Makefile b/Makefile index d6f8b7e..30c1e58 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ include $(DEVKITARM)/ds_rules #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -all: checkarm7 checkarm9 checkarm9_ak2 checkarm9_dsi $(TARGET).nds $(TARGET)_ak2.nds $(TARGET).dsi +all: checkarm7 checkarm9 checkarm9_ak2 checkarm9_dsi checkarm9_tt $(TARGET).nds $(TARGET)_ak2.nds $(TARGET)_tt.nds $(TARGET).dsi #--------------------------------------------------------------------------------- checkarm7: @@ -45,6 +45,10 @@ checkarm9_ak2: checkarm9_dsi: $(MAKE) -C arm9_dsi +#--------------------------------------------------------------------------------- +checkarm9_tt: + $(MAKE) -C arm9_tt + #--------------------------------------------------------------------------------- $(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \ @@ -57,6 +61,12 @@ $(TARGET)_ak2.nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9_ak2/$(TARGET).elf -b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \ $(_ADDFILES) +#--------------------------------------------------------------------------------- +$(TARGET)_tt.nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9_tt/$(TARGET).elf + ndstool -c $@ -7 arm7/$(TARGET).elf -9 arm9_tt/$(TARGET).elf \ + -b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \ + $(_ADDFILES) + #--------------------------------------------------------------------------------- $(TARGET).dsi : $(NITRO_FILES) arm7/$(TARGET).elf arm9_dsi/$(TARGET).elf ndstool -c $@ -7 arm7/$(TARGET).elf -9 arm9_dsi/$(TARGET).elf \ @@ -79,10 +89,15 @@ arm9_ak2/$(TARGET).elf: arm9_dsi/$(TARGET).elf: $(MAKE) -C arm9_dsi +#--------------------------------------------------------------------------------- +arm9_tt/$(TARGET).elf: + $(MAKE) -C arm9_tt + #--------------------------------------------------------------------------------- clean: $(MAKE) -C arm9 clean $(MAKE) -C arm9_ak2 clean $(MAKE) -C arm9_dsi clean + $(MAKE) -C arm9_tt clean $(MAKE) -C arm7 clean rm -f *.nds *.dsi diff --git a/arm7/source/main.cpp b/arm7/source/main.cpp index 9f5e72f..2cf8f01 100644 --- a/arm7/source/main.cpp +++ b/arm7/source/main.cpp @@ -40,6 +40,10 @@ static u32 getSystem(void) { return dsGen; } +static void prepairResetTT() { + memcpy(__NDSHeader->arm7destination, *(void* volatile*)0x02FFFE00, __NDSHeader->arm7binarySize); +} + static void prepairReset() { // enable sound if (2 == getSystem()) @@ -104,6 +108,8 @@ static void menuValue32Handler(u32 value, void* data) { swiChangeSoundBias(0, 0x400); swiSwitchToGBAMode(); } break; + case MENU_MSG_ARM7_REBOOT_TT: + prepairResetTT(); case MENU_MSG_ARM7_REBOOT: prepairReset(); swiSoftReset(); diff --git a/arm9/source/launcher/TopToyLauncher.cpp b/arm9/source/launcher/TopToyLauncher.cpp new file mode 100644 index 0000000..ff52ca9 --- /dev/null +++ b/arm9/source/launcher/TopToyLauncher.cpp @@ -0,0 +1,225 @@ +/* + Copyright (C) 2024 lifehackerhansol + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "../cheatwnd.h" +#include "../dsrom.h" +#include "../flags.h" +#include "../mainlist.h" +#include "../ui/progresswnd.h" +#include "ILauncher.h" +#include "TopToyLauncher.h" + +static void resetAndLoop() { + DC_FlushAll(); + DC_InvalidateAll(); + + fifoSendValue32(FIFO_USER_01, MENU_MSG_ARM7_REBOOT_TT); + *((vu32*)0x02FFFE04) = 0; + + // Interrupt + REG_IME = 0; + REG_IE = 0; + REG_IF = ~0; + + // wait for arm7 + while (*((vu32*)0x02FFFE04) == 0) + ; + swiSoftReset(); +} + +typedef struct { + char TTARMagic[4]; // usually "TTAR" + char gameCode[4]; // gameCode of title as seen in usrcheat.dat + u32 crc32; // crc32 of title header as seen in usrcheat.dat + u32 unk1; // TODO: what does this mean? + u32 cheatOffset; // relative from 0x1100 of file + u32 cheatSize; // size in bytes + u8 reserved[235]; +} PACKED TTARHeader; + +bool TopToyLauncher::prepareCheats() { + u32 gameCode, crc32; + + if (cCheatWnd::romData(mRomPath, gameCode, crc32)) { + FILE* cheatDb = fopen("/__rpg/cheats/usrcheat.dat", "rb"); + if (!cheatDb) goto cheat_failed; + long cheatOffset; + size_t cheatSize; + if (cCheatWnd::searchCheatData(cheatDb, gameCode, crc32, cheatOffset, cheatSize)) { + // Read cheat codes + cCheatWnd chtwnd((256) / 2, (192) / 2, 100, 100, NULL, mRomPath); + chtwnd.parse(mRomPath); + std::vector cheats(chtwnd.getCheats()); + + // YSMENU.ARP file creation + ALIGN(4) TTARHeader arHeader = {}; + arHeader.TTARMagic[0] = 'T'; + arHeader.TTARMagic[1] = 'T'; + arHeader.TTARMagic[2] = 'A'; + arHeader.TTARMagic[3] = 'R'; + memcpy(&arHeader.gameCode, &gameCode, 4); + arHeader.crc32 = crc32; + // We will write the cheat codes directly to 0x1100. + arHeader.cheatOffset = 0; + arHeader.cheatSize = cheats.size() << 2; + FILE* cheatFile = fopen("/YSMENU.ARP", "wb"); + fseek(cheatFile, 0, SEEK_SET); + // memdump. Actually just expanding the file seems to crash, but this works totally + // fine... + fwrite((void*)0x02400000, 4, 0x1100 >> 2, cheatFile); + fflush(cheatFile); + fseek(cheatFile, 0, SEEK_SET); + fwrite(&arHeader, 1, sizeof(TTARHeader), cheatFile); + fseek(cheatFile, 0x1100, SEEK_SET); + fwrite(cheats.data(), 4, cheats.size(), cheatFile); + fflush(cheatFile); + fclose(cheatFile); + } else { + fclose(cheatDb); + goto cheat_failed; + } + fclose(cheatDb); + } + + return true; + +cheat_failed: + // Remove cheat bin if exists + if (access("/YSMENU.ARP", F_OK) == 0) { + remove("/YSMENU.ARP"); + } + + return false; +} + +// TODO: what are the unknowns? +typedef struct { + char TTSYSMagic[4]; + u32 unk1; + u32 unk2; // always set to 1? + u32 softReset; + u32 useCheats; + u32 DMA; + u8 reserved[232]; +} PACKED TTSYSHeader; + +// TTMENU.SYS file creation. Sets up parameters for ttpatch.dat +bool TopToyLauncher::prepareTTSYS(void) { + TTSYSHeader* ttsys_header = (TTSYSHeader*)malloc(sizeof(TTSYSHeader)); + ttsys_header->TTSYSMagic[0] = 't'; + ttsys_header->TTSYSMagic[1] = 't'; + ttsys_header->TTSYSMagic[2] = 'd'; + ttsys_header->TTSYSMagic[3] = 's'; + ttsys_header->unk1 = 0; + ttsys_header->unk2 = 1; + ttsys_header->softReset = mFlags & PATCH_SOFT_RESET ? 1 : 0; + ttsys_header->useCheats = mFlags & PATCH_CHEATS ? 1 : 0; + ttsys_header->DMA = mFlags & PATCH_DMA ? 1 : 0; + + FILE* TTSYSFile = fopen("fat:/TTMENU.SYS", "rb+"); + fseek(TTSYSFile, 0, SEEK_SET); + fwrite(ttsys_header, sizeof(TTSYSHeader), 1, TTSYSFile); + free(ttsys_header); + fseek(TTSYSFile, 0x100, SEEK_SET); + fwrite(mRomPath.c_str() + 4, 1, 0x1000, TTSYSFile); + fseek(TTSYSFile, 0x1100, SEEK_SET); + fwrite(mSavePath.c_str() + 4, 1, 0x1000, TTSYSFile); + if (mFlags & PATCH_CHEATS) { + fseek(TTSYSFile, 0x2100, SEEK_SET); + fwrite("/YSMENU.ARP", 1, 0x12, TTSYSFile); + } + fflush(TTSYSFile); + fclose(TTSYSFile); + + return true; +} + +bool TopToyLauncher::launchRom(std::string romPath, std::string savePath, u32 flags, + u32 cheatOffset, u32 cheatSize) { +#ifdef __TTLAUNCHER_M3__ + if (access("fat:/TTMenu/m3patch.dat", F_OK) != 0) +#else + if (access("fat:/TTMenu/ttpatch.dat", F_OK) != 0) +#endif + return false; + + mRomPath = romPath; + mSavePath = savePath; + mFlags = flags; + + // Create TTMENU.SYS if it don't exist + if (access("fat:/TTMENU.SYS", F_OK) != 0) { + progressWnd().setTipText("Generating TTMENU.SYS..."); + progressWnd().show(); + progressWnd().setPercent(0); + FILE* TTSYSFile = fopen("fat:/TTMENU.SYS", "wb"); + fseek(TTSYSFile, 0, SEEK_SET); + // memdump. Actually just expanding the file seems to crash, but this works totally fine... + fwrite((void*)0x02400000, 1, 0x400000, TTSYSFile); + fflush(TTSYSFile); + fclose(TTSYSFile); + progressWnd().setPercent(100); + progressWnd().hide(); + } + + // Prepare cheat codes if enabled + if (flags & PATCH_CHEATS) { + if (!prepareCheats()) return false; + } + + // Setup TTMenu system parameters + if (!prepareTTSYS()) return false; + +#ifdef __TTLAUNCHER_M3__ + FILE* loader = fopen("fat:/TTMenu/m3patch.dat", "rb"); +#else + FILE* loader = fopen("fat:/TTMenu/ttpatch.dat", "rb"); +#endif + tNDSHeader* header = (tNDSHeader*)malloc(sizeof(tNDSHeader)); + u8* loader_arm7 = NULL; + fseek(loader, 0, SEEK_SET); + fread(header, 1, sizeof(tNDSHeader), loader); + fseek(loader, header->arm9romOffset, SEEK_SET); + fread((void*)header->arm9destination, 1, header->arm9binarySize, loader); + fseek(loader, header->arm7romOffset, SEEK_SET); + loader_arm7 = (u8*)memalign(32, header->arm7binarySize); + fread(loader_arm7, 1, header->arm7binarySize, loader); + fclose(loader); + memcpy((void*)__NDSHeader, header, sizeof(tNDSHeader)); + free(header); + *(u32*)0x02FFFE00 = (u32)loader_arm7; + + // patch a loop in ARM9 + // not sure why it's there. Some sort of obfuscation mechanism? + if (*((vu32*)0x023200EC) == 0xEAFFFFFE) // b #0; bad + *((vu32*)0x023200EC) = 0xE3A00000; // mov r0, #0 + + // ttpatch checks this for some reason + *((vu32*)0x02FFFC20) = 0x5555AAAA; + + // set SD/SDHC flag to SDHC, right now our DLDI only does SDHC + *((vu32*)0x02FFFC24) = ~0; + + // this int seems to be a flag to reinitialize the SD card in ttpatch + // if this is *not* -1, ttpatch sends an SDIO CMD12 (STOP_TRANSMISSION) + // other frontends set this to -1 by default, so let's do it too + *((vu32*)0x02FFFC28) = ~0; + + resetAndLoop(); + + free(loader_arm7); + + return false; +} diff --git a/arm9/source/launcher/TopToyLauncher.h b/arm9/source/launcher/TopToyLauncher.h new file mode 100644 index 0000000..1bb2d2b --- /dev/null +++ b/arm9/source/launcher/TopToyLauncher.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 2024 lifehackerhansol + + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +#pragma once + +#include +#include + +#include "ILauncher.h" + +class TopToyLauncher : public ILauncher { + public: + bool launchRom(std::string romPath, std::string savePath, u32 flags, u32 cheatOffset, + u32 cheatSize) override; + + private: + bool prepareCheats(void); + bool prepareTTSYS(void); + std::string mRomPath; + std::string mSavePath; + u32 mFlags; +}; diff --git a/arm9/source/romlauncher.cpp b/arm9/source/romlauncher.cpp index faa58f7..b415b1b 100644 --- a/arm9/source/romlauncher.cpp +++ b/arm9/source/romlauncher.cpp @@ -15,6 +15,7 @@ #include "launcher/HomebrewLauncher.h" #include "launcher/ILauncher.h" #include "launcher/NdsBootstrapLauncher.h" +#include "launcher/TopToyLauncher.h" static SAVE_TYPE PrefillGame(u32 aGameCode) { if (0x45444759 == aGameCode) // YGDE: 2209 - Diary Girl (USA) @@ -234,11 +235,15 @@ TLaunchResult launchRom(const std::string& aFullPath, DSRomInfo& aRomInfo, bool #ifndef __KERNEL_LAUNCHER_SUPPORT__ launcher = new NdsBootstrapLauncher(); -#else // __KERNEL_LAUNCHER_SUPPORT__ +#else // __KERNEL_LAUNCHER_SUPPORT__ if (aRomInfo.saveInfo().isNdsBootstrap()) launcher = new NdsBootstrapLauncher(); else +#ifdef __TTLAUNCHER__ + launcher = new TopToyLauncher(); +#else // __TTLAUNCHER__ launcher = new AcekardLauncher(); +#endif // __TTLAUNCHER__ #endif // __KERNEL_LAUNCHER_SUPPORT__ } else { if (!aMenu) saveManager().saveLastInfo(aFullPath); diff --git a/arm9_tt/Makefile b/arm9_tt/Makefile new file mode 100644 index 0000000..15e3696 --- /dev/null +++ b/arm9_tt/Makefile @@ -0,0 +1,141 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +SOURCE_PATH := ../arm9 +#--------------------------------------------------------------------------------- +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +# DATA is a list of directories containing binary files embedded using bin2o +# GRAPHICS is a list of directories containing image files to be converted with grit +# all directories are relative to this makefile +#--------------------------------------------------------------------------------- +BUILD := build +SOURCES := $(SOURCE_PATH)/source $(SOURCE_PATH)/source/ui $(SOURCE_PATH)/source/font $(SOURCE_PATH)/source/launcher $(SOURCE_PATH)/source/saves +INCLUDES := $(SOURCE_PATH)/include ../share $(SOURCES) +DATA := $(SOURCE_PATH)/data ../data +GRAPHICS := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s + +CFLAGS := -g -Wall -O3\ + $(ARCH) $(INCLUDE) -DARM9 + +CFLAGS += -D_NO_BOOTSTUB_ -D__KERNEL_LAUNCHER_SUPPORT__ -D__TTLAUNCHER__ + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lfat -lnds9 + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) $(PORTLIBS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export ARM9ELF := $(CURDIR)/$(TARGET).elf + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\ + $(foreach dir,$(DATA),$(CURDIR)/$(dir))\ + $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) + +export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export OFILES := $(PNGFILES:.png=.o) $(OFILES_BIN) $(OFILES_SOURCES) + +export HFILES := $(PNGFILES:.png=.h) $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\ + $(foreach dir,$(LIBDIRS),-I$(dir)/include)\ + -I$(CURDIR)/$(BUILD) +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(ARM9ELF) : $(OFILES) + @echo linking $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +# This rule creates assembly source files using grit +# grit takes an image file and a .grit describing how the file is to be processed +# add additional rules like this for each image extension +# you use in the graphics folders +#--------------------------------------------------------------------------------- +%.s %.h: %.png %.grit +#--------------------------------------------------------------------------------- + grit $< -fts -o$* + +-include $(DEPSDIR)/*.d + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/share/fifotool.h b/share/fifotool.h index 2abaccd..a1cfd14 100644 --- a/share/fifotool.h +++ b/share/fifotool.h @@ -18,3 +18,4 @@ #define MENU_MSG_BRIGHTNESS_SET2 10 #define MENU_MSG_BRIGHTNESS_SET3 11 #define MENU_MSG_SHUTDOWN 12 +#define MENU_MSG_ARM7_REBOOT_TT 13