diff --git a/GodMoDeS.pnproj b/GodMoDeS.pnproj new file mode 100644 index 0000000..24e0dd8 --- /dev/null +++ b/GodMoDeS.pnproj @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/GodMoDeS.pnps b/GodMoDeS.pnps new file mode 100644 index 0000000..a072584 --- /dev/null +++ b/GodMoDeS.pnps @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..84eee96 --- /dev/null +++ b/Makefile @@ -0,0 +1,193 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +.SECONDARY: + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +export VERSION_MAJOR := 1 +export VERSION_MINOR := 1 +export VERSION_PATCH := 0 + + +VERSION := $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# 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 +#--------------------------------------------------------------------------------- +TARGET := GodMoDeS +BUILD := build +SOURCES := source +INCLUDES := include source +DATA := data +GRAPHICS := gfx + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -O2 \ + -ffunction-sections -fdata-sections \ + -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm9.specs -g -Wl,--gc-sections $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project (order is important) +#--------------------------------------------------------------------------------- +LIBS := -lfat -lnds9 + + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# 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 TOPDIR := $(CURDIR) + +export OUTPUT := $(CURDIR)/$(TARGET) + +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))) +BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := load.bin bootstub.bin + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +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) + +icons := $(wildcard *.bmp) + +ifneq (,$(findstring $(TARGET).bmp,$(icons))) + export GAME_ICON := $(CURDIR)/$(TARGET).bmp +else + ifneq (,$(findstring icon.bmp,$(icons))) + export GAME_ICON := $(CURDIR)/icon.bmp + endif +endif + +export GAME_TITLE := $(TARGET) + +.PHONY: bootloader bootstub clean arm7/$(TARGET).elf arm9/$(TARGET).elf + +all: bootloader bootstub $(TARGET).nds + +dist: all + @rm -fr hbmenu + @mkdir hbmenu + @cp $(TARGET).nds hbmenu/BOOT.NDS + @cp BootStrap/_BOOT_MP.NDS BootStrap/TTMENU.DAT BootStrap/_DS_MENU.DAT BootStrap/ez5sys.bin BootStrap/akmenu4.nds hbmenu + @tar -cvjf $(TARGET)-$(VERSION).tar.bz2 hbmenu testfiles README.html COPYING hbmenu -X exclude.lst + +$(TARGET).nds: $(TARGET).arm7 $(TARGET).arm9 + ndstool -u 00030004 -g HGMA -c $(TARGET).nds -7 $(TARGET).arm7.elf -9 $(TARGET).arm9.elf\ + -b icon.bmp "GodMoDeS;Robz8" + +$(TARGET).arm7: arm7/$(TARGET).elf + cp arm7/$(TARGET).elf $(TARGET).arm7.elf + +$(TARGET).arm9: arm9/$(TARGET).elf + cp arm9/$(TARGET).elf $(TARGET).arm9.elf + +#--------------------------------------------------------------------------------- +arm7/$(TARGET).elf: + @$(MAKE) -C arm7 + +#--------------------------------------------------------------------------------- +arm9/$(TARGET).elf: + @$(MAKE) -C arm9 + +#--------------------------------------------------------------------------------- +#$(BUILD): + #@[ -d $@ ] || mkdir -p $@ + #@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr data + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds + @rm -fr $(TARGET).arm7.elf + @rm -fr $(TARGET).arm9.elf + @$(MAKE) -C bootloader clean + @$(MAKE) -C bootstub clean + @$(MAKE) -C arm9 clean + @$(MAKE) -C arm7 clean + +data: + @mkdir -p data + +bootloader: data + @$(MAKE) -C bootloader + +bootstub: data + @$(MAKE) -C bootstub + +#--------------------------------------------------------------------------------- +else + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +#$(OUTPUT).nds : $(OUTPUT).elf +#$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPSDIR)/*.d + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/arm7/Makefile b/arm7/Makefile new file mode 100644 index 0000000..703f32c --- /dev/null +++ b/arm7/Makefile @@ -0,0 +1,135 @@ +export ARM7_MAJOR := 0 +export ARM7_MINOR := 6 +export ARM7_PATCH := 0 + +VERSTRING := $(ARM7_MAJOR).$(ARM7_MINOR).$(ARM7_PATCH) +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM) +endif + +include $(DEVKITARM)/ds_rules +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# 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 +#--------------------------------------------------------------------------------- +TARGET := GodMoDeS +BUILD := build +SOURCES := source +INCLUDES := include build + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv4t -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -O2\ + -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM7 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map + + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lnds7 + + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + + +#--------------------------------------------------------------------------------- +# 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 VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export OUTPUT := $(CURDIR)/$(TARGET) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +.PHONY: all $(BUILD) clean + +all : $(BUILD) + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile + + +#--------------------------------------------------------------------------------- +dist: all +#--------------------------------------------------------------------------------- + @tar --exclude=*CVS* --exclude=.svn -cvjf default_arm7-src-$(VERSTRING).tar.bz2 source Makefile + @tar -cvjf default_arm7-$(VERSTRING).tar.bz2 default.elf + +#--------------------------------------------------------------------------------- +install: all +#--------------------------------------------------------------------------------- + cp $(TARGET).elf $(LIBNDS) + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).arm7 + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).elf : $(OFILES) $(LIBNDS)/lib/libnds7.a + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/arm7/ds_arm7_ram.ld b/arm7/ds_arm7_ram.ld new file mode 100644 index 0000000..52d6a5e --- /dev/null +++ b/arm7/ds_arm7_ram.ld @@ -0,0 +1,176 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +MEMORY { + rom : ORIGIN = 0x08000000, LENGTH = 32M + ram : ORIGIN = 0x2380000, LENGTH = 128K + iwram : ORIGIN = 0x037f8000, LENGTH = 96K +} + +__iwram_start = ORIGIN(iwram); +__iwram_top = ORIGIN(iwram)+ LENGTH(iwram); + +__sp_irq = __iwram_top - 0x100; +__sp_svc = __sp_irq - 0x100; +__sp_usr = __sp_svc - 0x100; + +__irq_flags = 0x04000000 - 8; +__irq_flagsaux = 0x04000000 - 0x40; +__irq_vector = 0x04000000 - 4; + +SECTIONS +{ + .init : + { + __text_start = . ; + KEEP (*(.init)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + .plt : { *(.plt) } >ram = 0xff + + .text : /* ALIGN (4): */ + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + + .fini : + { + KEEP (*(.fini)) + } >ram =0xff + + __text_end = . ; + + .rodata : + { + *(.rodata) + *all.rodata*(*) + *(.roda) + *(.rodata.*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ram + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ram + __exidx_end = .; + +/* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } >ram = 0xff + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } >ram = 0xff + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } >ram = 0xff + PROVIDE (__fini_array_end = .); + + .ctors : + { + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + + .eh_frame : + { + KEEP (*(.eh_frame)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ram = 0xff + .jcr : { KEEP (*(.jcr)) } >ram = 0 + .got : { *(.got.plt) *(.got) } >ram = 0 + + .data ALIGN(4) : { + __data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); + __data_end = ABSOLUTE(.) ; + } >ram = 0xff + + .bss ALIGN(4) : + { + __bss_start = ABSOLUTE(.); + __bss_start__ = ABSOLUTE(.); + *(.dynbss) + *(.gnu.linkonce.b*) + *(.bss*) + *(COMMON) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + __bss_end__ = ABSOLUTE(.); + __end__ = ABSOLUTE(.); + } >ram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .stack 0x80000 : { _stack = .; *(.stack) } + /* These must appear regardless of . */ +} diff --git a/arm7/source/main.c b/arm7/source/main.c new file mode 100644 index 0000000..7c8aab2 --- /dev/null +++ b/arm7/source/main.c @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------- + + default ARM7 core + + Copyright (C) 2005 - 2010 + Michael Noland (joat) + Jason Rogers (dovoto) + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ +#include +#include + +unsigned int * SCFG_EXT=(unsigned int*)0x4004008; + +//--------------------------------------------------------------------------------- +void ReturntoDSiMenu() { +//--------------------------------------------------------------------------------- + i2cWriteRegister(0x4A, 0x70, 0x01); // Bootflag = Warmboot/SkipHealthSafety + i2cWriteRegister(0x4A, 0x11, 0x01); // Reset to DSi Menu +} + +//--------------------------------------------------------------------------------- +void VblankHandler(void) { +//--------------------------------------------------------------------------------- + if(fifoCheckValue32(FIFO_USER_02)) { + ReturntoDSiMenu(); + } +} + +//--------------------------------------------------------------------------------- +void VcountHandler() { +//--------------------------------------------------------------------------------- + inputGetAndSend(); +} + +volatile bool exitflag = false; + +//--------------------------------------------------------------------------------- +void powerButtonCB() { +//--------------------------------------------------------------------------------- + exitflag = true; +} + +//--------------------------------------------------------------------------------- +int main() { +//--------------------------------------------------------------------------------- + nocashMessage("ARM7 main.c main"); + + // clear sound registers + dmaFillWords(0, (void*)0x04000400, 0x100); + + REG_SOUNDCNT |= SOUND_ENABLE; + writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP ); + powerOn(POWER_SOUND); + + readUserSettings(); + ledBlink(0); + + irqInit(); + // Start the RTC tracking IRQ + initClockIRQ(); + + //touchInit(); + + fifoInit(); + + SetYtrigger(80); + + installSystemFIFO(); + + irqSet(IRQ_VCOUNT, VcountHandler); + irqSet(IRQ_VBLANK, VblankHandler); + + irqEnable( IRQ_VBLANK | IRQ_VCOUNT ); + + setPowerButtonCB(powerButtonCB); + + fifoSendValue32(FIFO_USER_03, *SCFG_EXT); + fifoSendValue32(FIFO_USER_07, *(u16*)(0x4004700)); + fifoSendValue32(FIFO_USER_06, 1); + + // Keep the ARM7 mostly idle + while (!exitflag) { + if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) { + exitflag = true; + } + resyncClock(); + swiWaitForVBlank(); + } + return 0; +} + diff --git a/arm9/Makefile b/arm9/Makefile new file mode 100644 index 0000000..e0d29e4 --- /dev/null +++ b/arm9/Makefile @@ -0,0 +1,154 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# 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 +# MAXMOD_SOUNDBANK contains a directory of music and sound effect files +#--------------------------------------------------------------------------------- +TARGET := GodMoDeS +BUILD := build +SOURCES := source +INCLUDES := include source +DATA := ../data +GRAPHICS := ../gfx + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -O2\ + -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project (order is important) +#--------------------------------------------------------------------------------- +LIBS := -lfat -lnds9 + + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) ../ $(LIBNDS) + +#--------------------------------------------------------------------------------- +# 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 OUTPUT := $(CURDIR)/$(TARGET) + +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))) +BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +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 := $(addsuffix .o,$(BINFILES)) \ + $(BMPFILES:.bmp=.o) \ + $(PNGFILES:.png=.o) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +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) + + +export OUTPUT := $(CURDIR)/$(TARGET) + +.PHONY: $(BUILD) clean + +all : $(BUILD) + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds *.bin + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.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 : %.bmp %.grit +#--------------------------------------------------------------------------------- + grit $< -fts -o$* + + +#--------------------------------------------------------------------------------- +%.s %.h : %.png %.grit +#--------------------------------------------------------------------------------- + grit $< -fts -o$* + +-include $(DEPSDIR)/*.d + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/arm9/source/date.cpp b/arm9/source/date.cpp new file mode 100644 index 0000000..840fe18 --- /dev/null +++ b/arm9/source/date.cpp @@ -0,0 +1,110 @@ +#include "date.h" + +#include +#include +#include + +#include +using std::string; + +/** + * Get the current date as a C string. + * @param format Date format. + * @param buf Output buffer. + * @param size Size of the output buffer. + * @return Number of bytes written, excluding the NULL terminator. + * @return Current date. (Caller must free() this string.) + */ +size_t GetDate(DateFormat format, char *buf, size_t size) +{ + time_t Raw; + time(&Raw); + const struct tm *Time = localtime(&Raw); + + switch (format) { + case FORMAT_YDM: + return strftime(buf, size, "%Y-%d-%m_%k-%M", Time); + case FORMAT_YMD: + return strftime(buf, size, "%Y-%m-%d_%k-%M", Time); + case FORMAT_DM: + return strftime(buf, size, "%d/%m", Time); // Ex: 26/12 + case FORMAT_MD: + return strftime(buf, size, "%m/%d", Time); // Ex: 12/26 + case FORMAT_M_D: + return strftime(buf, size, "%d.%m.", Time); // Ex: 26.12. + case FORMAT_MY: + return strftime(buf, size, "%m %Y", Time); + case FORMAT_M: + return strftime(buf, size, "%m", Time); + case FORMAT_Y: + return strftime(buf, size, "%Y", Time); + default: + break; + } + + // Invalid format. + // Should not get here... + if (size > 0) { + *buf = 0; + } + return 0; +} + +/** + * Get the current time formatted for the top bar. + * @return std::string containing the time. + */ +string RetTime() +{ + time_t Raw; + time(&Raw); + const struct tm *Time = localtime(&Raw); + + char Tmp[24]; + strftime(Tmp, sizeof(Tmp), "%k:%M", Time); + + return string(Tmp); +} + +/** + * Draw the date using the specified format. + * @param Xpos X position. + * @param Ypos Y position. + * @param size Text size. + * @param format Date format. + */ +char* DrawDateF(DateFormat format) +{ + char date_str[24]; + GetDate(format, date_str, sizeof(date_str)); + if (date_str[0] == 0) + return ""; + return date_str; +} + +/** + * Draw the date. + * Date format depends on language setting. + * @param screen Top or Bottom screen. + * @param Xpos X position. + * @param Ypos Y position. + * @param size Text size. + */ +char* DrawDate() +{ + // Date formats. + // - Index: Language ID. + // - Value: Date format. + static const uint8_t date_fmt[8] = { + FORMAT_MD, // Japanese + FORMAT_MD, // English + FORMAT_DM, // French + FORMAT_M_D, // German + FORMAT_DM, // Italian + FORMAT_DM, // Spanish + FORMAT_MD, // Chinese + FORMAT_MD, // Korean + }; + + return DrawDateF((DateFormat)date_fmt[PersonalData->language]); +} diff --git a/arm9/source/date.h b/arm9/source/date.h new file mode 100644 index 0000000..d712d4d --- /dev/null +++ b/arm9/source/date.h @@ -0,0 +1,47 @@ +#ifndef DATE_H +#define DATE_H + +#include +#include +#include + +typedef enum { + FORMAT_YDM = 0, + FORMAT_YMD = 1, + FORMAT_DM = 2, + FORMAT_MD = 3, + FORMAT_M_D = 4, + FORMAT_MY = 5, + FORMAT_M = 6, + FORMAT_Y = 7, +} DateFormat; + +/** + * Get the current date as a C string. + * @param format Date format. + * @param buf Output buffer. + * @param size Size of the output buffer. + * @return Number of bytes written, excluding the NULL terminator. + * @return Current date. (Caller must free() this string.) + */ +size_t GetDate(DateFormat format, char *buf, size_t size); + +/** + * Get the current time formatted for the top bar. + * @return std::string containing the time. + */ +std::string RetTime(); + +/** + * Draw the date using the specified format. + * @param format Date format. + */ +char* DrawDateF(DateFormat format); + +/** + * Draw the month and year using the specified color. + * Format is selected based on the language setting. + */ +char* DrawDate(void); + +#endif // DATE_H diff --git a/arm9/source/fileOperations.cpp b/arm9/source/fileOperations.cpp new file mode 100644 index 0000000..3a0a56c --- /dev/null +++ b/arm9/source/fileOperations.cpp @@ -0,0 +1,69 @@ +#include +#include + +u32 copyBuf[0x8000]; + +off_t getFileSize(const char *fileName) +{ + FILE* fp = fopen(fileName, "rb"); + off_t fsize = 0; + if (fp) { + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); // Get source file's size + fseek(fp, 0, SEEK_SET); + } + fclose(fp); + + return fsize; +} + +int fcopy(const char *sourcePath, const char *destinationPath) +{ + FILE* sourceFile = fopen(sourcePath, "rb"); + off_t fsize = 0; + if (sourceFile) { + fseek(sourceFile, 0, SEEK_END); + fsize = ftell(sourceFile); // Get source file's size + fseek(sourceFile, 0, SEEK_SET); + } else { + fclose(sourceFile); + return -1; + } + + FILE* destinationFile = fopen(destinationPath, "wb"); + //if (destinationFile) { + fseek(destinationFile, 0, SEEK_SET); + /*} else { + fclose(sourceFile); + fclose(destinationFile); + return -1; + }*/ + + off_t offset = 0; + int numr; + while (1) + { + /* scanKeys(); + if (keysHeld() & KEY_A) { + // Cancel copying + fclose(sourceFile); + fclose(destinationFile); + return -1; + break; + } */ + + // Copy file to destination path + numr = fread(copyBuf, 2, 0x8000, sourceFile); + fwrite(copyBuf, 2, numr, destinationFile); + offset += 0x8000; + + if (offset > fsize) { + fclose(sourceFile); + fclose(destinationFile); + return 1; + break; + } + } + + return -1; +} diff --git a/arm9/source/fileOperations.h b/arm9/source/fileOperations.h new file mode 100644 index 0000000..ad38836 --- /dev/null +++ b/arm9/source/fileOperations.h @@ -0,0 +1,7 @@ +#ifndef FILE_COPY +#define FILE_COPY + +off_t getFileSize(const char *fileName); +int fcopy(const char *sourcePath, const char *destinationPath); + +#endif // FILE_COPY \ No newline at end of file diff --git a/arm9/source/file_browse.cpp b/arm9/source/file_browse.cpp new file mode 100644 index 0000000..92e7ab7 --- /dev/null +++ b/arm9/source/file_browse.cpp @@ -0,0 +1,245 @@ +/*----------------------------------------------------------------- + Copyright (C) 2005 - 2013 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + Claudio "sverx" + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ + +#include "file_browse.h" +#include +#include +#include +#include +#include +#include + +#include + +#include "date.h" +#include "fileOperations.h" + +#define SCREEN_COLS 32 +#define ENTRIES_PER_SCREEN 22 +#define ENTRIES_START_ROW 2 +#define ENTRY_PAGE_LENGTH 10 + +using namespace std; + +struct DirEntry { + string name; + bool isDirectory; +} ; + +bool nameEndsWith (const string& name, const vector extensionList) { + + if (name.size() == 0) return false; + + if (extensionList.size() == 0) return true; + + for (int i = 0; i < (int)extensionList.size(); i++) { + const string ext = extensionList.at(i); + if ( strcasecmp (name.c_str() + name.size() - ext.size(), ext.c_str()) == 0) return true; + } + return false; +} + +bool dirEntryPredicate (const DirEntry& lhs, const DirEntry& rhs) { + + if (!lhs.isDirectory && rhs.isDirectory) { + return false; + } + if (lhs.isDirectory && !rhs.isDirectory) { + return true; + } + return strcasecmp(lhs.name.c_str(), rhs.name.c_str()) < 0; +} + +void getDirectoryContents (vector& dirContents, const vector extensionList) { + struct stat st; + + dirContents.clear(); + + DIR *pdir = opendir ("."); + + if (pdir == NULL) { + iprintf ("Unable to open the directory.\n"); + } else { + + while(true) { + DirEntry dirEntry; + + struct dirent* pent = readdir(pdir); + if(pent == NULL) break; + + stat(pent->d_name, &st); + dirEntry.name = pent->d_name; + dirEntry.isDirectory = (st.st_mode & S_IFDIR) ? true : false; + + if (dirEntry.name.compare(".") != 0 && (dirEntry.isDirectory || nameEndsWith(dirEntry.name, extensionList))) { + dirContents.push_back (dirEntry); + } + + } + + closedir(pdir); + } + + sort(dirContents.begin(), dirContents.end(), dirEntryPredicate); +} + +void getDirectoryContents (vector& dirContents) { + vector extensionList; + getDirectoryContents (dirContents, extensionList); +} + +void showDirectoryContents (const vector& dirContents, int startRow) { + char path[PATH_MAX]; + + + getcwd(path, PATH_MAX); + + // Clear the screen + iprintf ("\x1b[2J"); + + // Print the path + if (strlen(path) < SCREEN_COLS) { + iprintf ("%s", path); + } else { + iprintf ("%s", path + strlen(path) - SCREEN_COLS); + } + + // Move to 2nd row + iprintf ("\x1b[1;0H"); + // Print line of dashes + iprintf ("--------------------------------"); + + // Print directory listing + for (int i = 0; i < ((int)dirContents.size() - startRow) && i < ENTRIES_PER_SCREEN; i++) { + const DirEntry* entry = &dirContents.at(i + startRow); + char entryName[SCREEN_COLS + 1]; + + // Set row + iprintf ("\x1b[%d;0H", i + ENTRIES_START_ROW); + + if (entry->isDirectory) { + strncpy (entryName, entry->name.c_str(), SCREEN_COLS); + entryName[SCREEN_COLS - 3] = '\0'; + iprintf (" [%s]", entryName); + } else { + strncpy (entryName, entry->name.c_str(), SCREEN_COLS); + entryName[SCREEN_COLS - 1] = '\0'; + iprintf (" %s", entryName); + } + } +} + +string browseForFile (const vector extensionList) { + int pressed = 0; + int screenOffset = 0; + int fileOffset = 0; + off_t fileSize = 0; + vector dirContents; + + getDirectoryContents (dirContents, extensionList); + + while (true) { + consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); + //consoleClear(); + DirEntry* entry = &dirContents.at(fileOffset); + printf (entry->name.c_str()); + printf ("\n"); + if (entry->isDirectory) { + printf ("(dir)"); + } else { + fileSize = getFileSize(entry->name.c_str()); + iprintf ("%i Bytes", (int)fileSize); + } + iprintf ("\x1b[23;0H"); + printf ("GodMoDeS v0.1.0"); + + consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); + //consoleClear(); + showDirectoryContents (dirContents, screenOffset); + + // Clear old cursors + /*for (int i = ENTRIES_START_ROW; i < ENTRIES_PER_SCREEN + ENTRIES_START_ROW; i++) { + iprintf ("\x1b[%d;0H ", i); + }*/ + // Show cursor + iprintf ("\x1b[%d;0H*", fileOffset - screenOffset + ENTRIES_START_ROW); + + //iconTitleUpdate (dirContents.at(fileOffset).isDirectory,dirContents.at(fileOffset).name.c_str()); + + // Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do + do { + // Move to right side of screen + iprintf ("\x1b[0;27H"); + // Print time + printf (RetTime().c_str()); + + scanKeys(); + pressed = keysDownRepeat(); + swiWaitForVBlank(); + } while (!pressed); + + if (pressed & KEY_UP) fileOffset -= 1; + if (pressed & KEY_DOWN) fileOffset += 1; + if (pressed & KEY_LEFT) fileOffset -= ENTRY_PAGE_LENGTH; + if (pressed & KEY_RIGHT) fileOffset += ENTRY_PAGE_LENGTH; + + if (fileOffset < 0) fileOffset = dirContents.size() - 1; // Wrap around to bottom of list + if (fileOffset > ((int)dirContents.size() - 1)) fileOffset = 0; // Wrap around to top of list + + // Scroll screen if needed + if (fileOffset < screenOffset) { + screenOffset = fileOffset; + showDirectoryContents (dirContents, screenOffset); + } + if (fileOffset > screenOffset + ENTRIES_PER_SCREEN - 1) { + screenOffset = fileOffset - ENTRIES_PER_SCREEN + 1; + showDirectoryContents (dirContents, screenOffset); + } + + if (pressed & KEY_A) { + DirEntry* entry = &dirContents.at(fileOffset); + if (entry->isDirectory) { + iprintf("Entering directory\n"); + // Enter selected directory + chdir (entry->name.c_str()); + getDirectoryContents (dirContents, extensionList); + screenOffset = 0; + fileOffset = 0; + showDirectoryContents (dirContents, screenOffset); + } else { + // Clear the screen + iprintf ("\x1b[2J"); + // Return the chosen file + return entry->name; + } + } + + if (pressed & KEY_B) { + // Go up a directory + chdir (".."); + getDirectoryContents (dirContents, extensionList); + screenOffset = 0; + fileOffset = 0; + showDirectoryContents (dirContents, screenOffset); + } + } +} diff --git a/arm9/source/file_browse.h b/arm9/source/file_browse.h new file mode 100644 index 0000000..d811c40 --- /dev/null +++ b/arm9/source/file_browse.h @@ -0,0 +1,32 @@ +/*----------------------------------------------------------------- + Copyright (C) 2005 - 2010 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ + +#ifndef FILE_BROWSE_H +#define FILE_BROWSE_H + +#include +#include + +std::string browseForFile (const std::vector extensionList); + + + +#endif //FILE_BROWSE_H diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp new file mode 100644 index 0000000..d79d767 --- /dev/null +++ b/arm9/source/main.cpp @@ -0,0 +1,145 @@ +/*----------------------------------------------------------------- + Copyright (C) 2005 - 2013 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + Claudio "sverx" + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ +#include +#include +#include +#include +#include + +#include +#include + +#include "nds_loader_arm9.h" +#include "file_browse.h" + +//#include "iconTitle.h" + +using namespace std; + +//--------------------------------------------------------------------------------- +void stop (void) { +//--------------------------------------------------------------------------------- + while (1) { + swiWaitForVBlank(); + } +} + +char filePath[PATH_MAX]; + +//--------------------------------------------------------------------------------- +int main(int argc, char **argv) { +//--------------------------------------------------------------------------------- + + // overwrite reboot stub identifier + extern u64 *fake_heap_end; + *fake_heap_end = 0; + + defaultExceptionHandler(); + + int pathLen; + std::string filename; + + //iconTitleInit(); + + // Subscreen as a console + videoSetMode(MODE_0_2D); + vramSetBankG(VRAM_G_MAIN_BG); + videoSetModeSub(MODE_0_2D); + vramSetBankH(VRAM_H_SUB_BG); + consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true); + + if (!fatInitDefault()) { + iprintf ("fatinitDefault failed!\n"); + stop(); + } + + keysSetRepeat(25,5); + + vector extensionList; + extensionList.push_back(".nds"); + extensionList.push_back(".firm"); + //extensionList.push_back(".argv"); + + chdir("/nds"); + + while(1) { + + filename = browseForFile(extensionList); + + // Construct a command line + getcwd (filePath, PATH_MAX); + pathLen = strlen (filePath); + vector argarray; + + if ( strcasecmp (filename.c_str() + filename.size() - 5, ".argv") == 0) { + + FILE *argfile = fopen(filename.c_str(),"rb"); + char str[PATH_MAX], *pstr; + const char seps[]= "\n\r\t "; + + while( fgets(str, PATH_MAX, argfile) ) { + // Find comment and end string there + if( (pstr = strchr(str, '#')) ) + *pstr= '\0'; + + // Tokenize arguments + pstr= strtok(str, seps); + + while( pstr != NULL ) { + argarray.push_back(strdup(pstr)); + pstr= strtok(NULL, seps); + } + } + fclose(argfile); + filename = argarray.at(0); + } else { + argarray.push_back(strdup(filename.c_str())); + } + + if ( strcasecmp (filename.c_str() + filename.size() - 4, ".nds") != 0 || argarray.size() == 0 ) { + iprintf("no nds file specified\n"); + } else { + char *name = argarray.at(0); + strcpy (filePath + pathLen, name); + free(argarray.at(0)); + argarray.at(0) = filePath; + iprintf ("Running %s with %d parameters\n", argarray[0], argarray.size()); + int err = runNdsFile (argarray[0], argarray.size(), (const char **)&argarray[0]); + iprintf ("Start failed. Error %i\n", err); + + } + + while(argarray.size() !=0 ) { + free(argarray.at(0)); + argarray.erase(argarray.begin()); + } + + while (1) { + swiWaitForVBlank(); + scanKeys(); + if (!(keysHeld() & KEY_A)) break; + } + + } + + return 0; +} diff --git a/arm9/source/nds_loader_arm9.c b/arm9/source/nds_loader_arm9.c new file mode 100644 index 0000000..c5dc700 --- /dev/null +++ b/arm9/source/nds_loader_arm9.c @@ -0,0 +1,436 @@ +/*----------------------------------------------------------------- + Copyright (C) 2005 - 2010 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ +#include +#include +#include +#include +#include + +#include +#include + +#include "load_bin.h" + +#ifndef _NO_BOOTSTUB_ +#include "bootstub_bin.h" +#endif + +#include "nds_loader_arm9.h" +#define LCDC_BANK_C (u16*)0x06840000 +#define STORED_FILE_CLUSTER (*(((u32*)LCDC_BANK_C) + 1)) +#define INIT_DISC (*(((u32*)LCDC_BANK_C) + 2)) +#define WANT_TO_PATCH_DLDI (*(((u32*)LCDC_BANK_C) + 3)) + + +/* + b startUp + +storedFileCluster: + .word 0x0FFFFFFF @ default BOOT.NDS +initDisc: + .word 0x00000001 @ init the disc by default +wantToPatchDLDI: + .word 0x00000001 @ by default patch the DLDI section of the loaded NDS +@ Used for passing arguments to the loaded app +argStart: + .word _end - _start +argSize: + .word 0x00000000 +dldiOffset: + .word _dldi_start - _start +dsiSD: + .word 0 +dsiMode: + .word 0 +*/ + +#define STORED_FILE_CLUSTER_OFFSET 4 +#define INIT_DISC_OFFSET 8 +#define WANT_TO_PATCH_DLDI_OFFSET 12 +#define ARG_START_OFFSET 16 +#define ARG_SIZE_OFFSET 20 +#define HAVE_DSISD_OFFSET 28 +#define DSIMODE_OFFSET 32 + + +typedef signed int addr_t; +typedef unsigned char data_t; + +#define FIX_ALL 0x01 +#define FIX_GLUE 0x02 +#define FIX_GOT 0x04 +#define FIX_BSS 0x08 + +enum DldiOffsets { + DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm" + DO_magicToken = 0x00, // 0xBF8DA5ED + DO_magicShortString = 0x04, // " Chishm" + DO_version = 0x0C, + DO_driverSize = 0x0D, + DO_fixSections = 0x0E, + DO_allocatedSpace = 0x0F, + + DO_friendlyName = 0x10, + + DO_text_start = 0x40, // Data start + DO_data_end = 0x44, // Data end + DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing + DO_glue_end = 0x4C, // Interworking glue end + DO_got_start = 0x50, // GOT start -- Needs address fixing + DO_got_end = 0x54, // GOT end + DO_bss_start = 0x58, // bss start -- Needs setting to zero + DO_bss_end = 0x5C, // bss end + + // IO_INTERFACE data + DO_ioType = 0x60, + DO_features = 0x64, + DO_startup = 0x68, + DO_isInserted = 0x6C, + DO_readSectors = 0x70, + DO_writeSectors = 0x74, + DO_clearStatus = 0x78, + DO_shutdown = 0x7C, + DO_code = 0x80 +}; + +static addr_t readAddr (data_t *mem, addr_t offset) { + return ((addr_t*)mem)[offset/sizeof(addr_t)]; +} + +static void writeAddr (data_t *mem, addr_t offset, addr_t value) { + ((addr_t*)mem)[offset/sizeof(addr_t)] = value; +} + +static void vramcpy (void* dst, const void* src, int len) +{ + u16* dst16 = (u16*)dst; + u16* src16 = (u16*)src; + + //dmaCopy(src, dst, len); + + for ( ; len > 0; len -= 2) { + *dst16++ = *src16++; + } +} + +static addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) { + const int* dataChunk = (const int*) data; + int searchChunk = ((const int*)search)[0]; + addr_t i; + addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int)); + + for ( i = 0; i < dataChunkEnd; i++) { + if (dataChunk[i] == searchChunk) { + if ((i*sizeof(int) + searchLen) > dataLen) { + return -1; + } + if (memcmp (&data[i*sizeof(int)], search, searchLen) == 0) { + return i*sizeof(int); + } + } + } + + return -1; +} + +// Normal DLDI uses "\xED\xA5\x8D\xBF Chishm" +// Bootloader string is different to avoid being patched +static const data_t dldiMagicLoaderString[] = "\xEE\xA5\x8D\xBF Chishm"; // Different to a normal DLDI file + +#define DEVICE_TYPE_DLDI 0x49444C44 + +static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) +{ + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + addr_t patchOffset; // Position of patch destination in the file + addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly + addr_t ddmemOffset; // Original offset used in the DLDI file + addr_t ddmemStart; // Start of range that offsets can be in the DLDI file + addr_t ddmemEnd; // End of range that offsets can be in the DLDI file + addr_t ddmemSize; // Size of range that offsets can be in the DLDI file + + addr_t addrIter; + + data_t *pDH; + data_t *pAH; + + size_t dldiFileSize = 0; + + // Find the DLDI reserved space in the file + patchOffset = quickFind (binData, dldiMagicLoaderString, binSize, sizeof(dldiMagicLoaderString)); + + if (patchOffset < 0) { + // does not have a DLDI section + return false; + } + + pDH = (data_t*)(io_dldi_data); + + pAH = &(binData[patchOffset]); + + if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) { + // No DLDI patch + return false; + } + + if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) { + // Not enough space for patch + return false; + } + + dldiFileSize = 1 << pDH[DO_driverSize]; + + memOffset = readAddr (pAH, DO_text_start); + if (memOffset == 0) { + memOffset = readAddr (pAH, DO_startup) - DO_code; + } + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Remember how much space is actually reserved + pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; + // Copy the DLDI patch into the application + vramcpy (pAH, pDH, dldiFileSize); + + // Fix the section pointers in the header + writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); + writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset); + writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset); + writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset); + writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset); + writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset); + writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset); + writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset); + writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset); + writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset); + writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset); + writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset); + writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset); + + if (pDH[DO_fixSections] & FIX_ALL) { + // Search through and fix pointers within the data section of the file + for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_GLUE) { + // Search through and fix pointers within the glue section of the file + for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_GOT) { + // Search through and fix pointers within the Global Offset Table section of the file + for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (clearBSS && (pDH[DO_fixSections] & FIX_BSS)) { + // Initialise the BSS to 0, only if the disc is being re-inited + memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } + + return true; +} + +int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool dldiPatchNds, int argc, const char** argv) +{ + char* argStart; + u16* argData; + u16 argTempVal = 0; + int argSize; + const char* argChar; + + irqDisable(IRQ_ALL); + + // Direct CPU access to VRAM bank C + VRAM_C_CR = VRAM_ENABLE | VRAM_C_LCD; + // Load the loader/patcher into the correct address + vramcpy (LCDC_BANK_C, loader, loaderSize); + + // Set the parameters for the loader + // STORED_FILE_CLUSTER = cluster; + writeAddr ((data_t*) LCDC_BANK_C, STORED_FILE_CLUSTER_OFFSET, cluster); + // INIT_DISC = initDisc; + writeAddr ((data_t*) LCDC_BANK_C, INIT_DISC_OFFSET, initDisc); + + writeAddr ((data_t*) LCDC_BANK_C, DSIMODE_OFFSET, isDSiMode()); + if(argv[0][0]=='s' && argv[0][1]=='d') { + dldiPatchNds = false; + writeAddr ((data_t*) LCDC_BANK_C, HAVE_DSISD_OFFSET, 1); + } + + // WANT_TO_PATCH_DLDI = dldiPatchNds; + writeAddr ((data_t*) LCDC_BANK_C, WANT_TO_PATCH_DLDI_OFFSET, dldiPatchNds); + // Give arguments to loader + argStart = (char*)LCDC_BANK_C + readAddr((data_t*)LCDC_BANK_C, ARG_START_OFFSET); + argStart = (char*)(((int)argStart + 3) & ~3); // Align to word + argData = (u16*)argStart; + argSize = 0; + + for (; argc > 0 && *argv; ++argv, --argc) + { + for (argChar = *argv; *argChar != 0; ++argChar, ++argSize) + { + if (argSize & 1) + { + argTempVal |= (*argChar) << 8; + *argData = argTempVal; + ++argData; + } + else + { + argTempVal = *argChar; + } + } + if (argSize & 1) + { + *argData = argTempVal; + ++argData; + } + argTempVal = 0; + ++argSize; + } + *argData = argTempVal; + + writeAddr ((data_t*) LCDC_BANK_C, ARG_START_OFFSET, (addr_t)argStart - (addr_t)LCDC_BANK_C); + writeAddr ((data_t*) LCDC_BANK_C, ARG_SIZE_OFFSET, argSize); + + + if(dldiPatchNds) { + // Patch the loader with a DLDI for the card + if (!dldiPatchLoader ((data_t*)LCDC_BANK_C, loaderSize, initDisc)) { + return 3; + } + } + + irqDisable(IRQ_ALL); + + // Give the VRAM to the ARM7 + VRAM_C_CR = VRAM_ENABLE | VRAM_C_ARM7_0x06000000; + // Reset into a passme loop + REG_EXMEMCNT |= ARM7_OWNS_ROM | ARM7_OWNS_CARD; + *((vu32*)0x02FFFFFC) = 0; + *((vu32*)0x02FFFE04) = (u32)0xE59FF018; + *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; + + resetARM7(0x06000000); + + swiSoftReset(); + return true; +} + +int runNdsFile (const char* filename, int argc, const char** argv) { + struct stat st; + char filePath[PATH_MAX]; + int pathLen; + const char* args[1]; + + + if (stat (filename, &st) < 0) { + return 1; + } + + if (argc <= 0 || !argv) { + // Construct a command line if we weren't supplied with one + if (!getcwd (filePath, PATH_MAX)) { + return 2; + } + pathLen = strlen (filePath); + strcpy (filePath + pathLen, filename); + args[0] = filePath; + argv = args; + } + + bool havedsiSD = false; + + if(argv[0][0]=='s' && argv[0][1]=='d') havedsiSD = true; + + installBootStub(havedsiSD); + + return runNds (load_bin, load_bin_size, st.st_ino, true, true, argc, argv); +} + +/* + b startUp + +storedFileCluster: + .word 0x0FFFFFFF @ default BOOT.NDS +initDisc: + .word 0x00000001 @ init the disc by default +wantToPatchDLDI: + .word 0x00000001 @ by default patch the DLDI section of the loaded NDS +@ Used for passing arguments to the loaded app +argStart: + .word _end - _start +argSize: + .word 0x00000000 +dldiOffset: + .word _dldi_start - _start +dsiSD: + .word 0 +*/ +bool installBootStub(bool havedsiSD) { +#ifndef _NO_BOOTSTUB_ + extern char *fake_heap_end; + struct __bootstub *bootstub = (struct __bootstub *)fake_heap_end; + u32 *bootloader = (u32*)(fake_heap_end+bootstub_bin_size); + + memcpy(bootstub,bootstub_bin,bootstub_bin_size); + memcpy(bootloader,load_bin,load_bin_size); + bool ret = false; + + bootloader[8] = isDSiMode(); + if( havedsiSD) { + ret = true; + bootloader[3] = 0; // don't dldi patch + bootloader[7] = 1; // use internal dsi SD code + } else { + ret = dldiPatchLoader((data_t*)bootloader, load_bin_size,false); + } + bootstub->arm9reboot = (VoidFn)(((u32)bootstub->arm9reboot)+fake_heap_end); + bootstub->arm7reboot = (VoidFn)(((u32)bootstub->arm7reboot)+fake_heap_end); + bootstub->bootsize = load_bin_size; + + DC_FlushAll(); + + return ret; +#else + return true; +#endif + +} + diff --git a/arm9/source/nds_loader_arm9.h b/arm9/source/nds_loader_arm9.h new file mode 100644 index 0000000..8d03d77 --- /dev/null +++ b/arm9/source/nds_loader_arm9.h @@ -0,0 +1,42 @@ +/*----------------------------------------------------------------- + Copyright (C) 2005 - 2010 + Michael "Chishm" Chisholm + Dave "WinterMute" Murphy + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ + +#ifndef NDS_LOADER_ARM9_H +#define NDS_LOADER_ARM9_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOAD_DEFAULT_NDS 0 + +int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool dldiPatchNds, int argc, const char** argv); + +int runNdsFile (const char* filename, int argc, const char** argv); + +bool installBootStub(bool havedsiSD); + +#ifdef __cplusplus +} +#endif + +#endif // NDS_LOADER_ARM7_H diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000..437ac39 --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,123 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM) +endif + +-include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# 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 +#--------------------------------------------------------------------------------- +TARGET := load +BUILD ?= build +SOURCES := source source/patches +INCLUDES := build +SPECS := specs + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -g -Wall -Os\ + -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) $(EXTRA_CFLAGS) -DARM7 + +ASFLAGS := -g $(ARCH) $(EXTRA_CFLAGS) $(INCLUDE) +LDFLAGS = -nostartfiles -T $(TOPDIR)/load.ld -g $(ARCH) -Wl,-Map,$(TARGET).map + +LIBS := -lnds7 + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + + +#--------------------------------------------------------------------------------- +# 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 TOPDIR := $(CURDIR) +export LOADBIN := $(CURDIR)/../data/$(TARGET).bin +export LOADELF := $(CURDIR)/$(TARGET).elf +export DEPSDIR := $(CURDIR)/$(BUILD) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +#--------------------------------------------------------------------------------- +# use CC for linking standard C +#--------------------------------------------------------------------------------- +export LD := $(CC) +#--------------------------------------------------------------------------------- + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf *.bin + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(LOADBIN) : $(LOADELF) + @$(OBJCOPY) -O binary $< $@ + @echo built ... $(notdir $@) + + +$(LOADELF) : $(OFILES) + @echo linking $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + +arm9mpu_reset.o: mpu_reset.bin + +mpu_reset.bin: mpu_reset.elf + $(OBJCOPY) -O binary $< $@ + +mpu_reset.elf: $(TOPDIR)/arm9code/mpu_reset.s + $(CC) $(ASFLAGS) -Ttext=0 -x assembler-with-cpp -nostartfiles -nostdlib $< -o $@ + +-include $(DEPENDS) +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/bootloader/arm9code/mpu_reset.s b/bootloader/arm9code/mpu_reset.s new file mode 100644 index 0000000..3d499dd --- /dev/null +++ b/bootloader/arm9code/mpu_reset.s @@ -0,0 +1,110 @@ +/* + Copyright 2006 - 2015 Dave Murphy (WinterMute) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include + + .text + .align 4 + + .arm + + .arch armv5te + .cpu arm946e-s + +@--------------------------------------------------------------------------------- + .global _start + .type _start STT_FUNC +@--------------------------------------------------------------------------------- +_start: +@--------------------------------------------------------------------------------- + @ Switch off MPU + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #PROTECT_ENABLE + mcr p15, 0, r0, c1, c0, 0 + + + adr r12, mpu_initial_data + ldmia r12, {r0-r10} + + mcr p15, 0, r0, c2, c0, 0 + mcr p15, 0, r0, c2, c0, 1 + mcr p15, 0, r1, c3, c0, 0 + mcr p15, 0, r2, c5, c0, 2 + mcr p15, 0, r3, c5, c0, 3 + mcr p15, 0, r4, c6, c0, 0 + mcr p15, 0, r5, c6, c1, 0 + mcr p15, 0, r6, c6, c3, 0 + mcr p15, 0, r7, c6, c4, 0 + mcr p15, 0, r8, c6, c6, 0 + mcr p15, 0, r9, c6, c7, 0 + mcr p15, 0, r10, c9, c1, 0 + + mov r0, #0 + mcr p15, 0, r0, c6, c2, 0 @ PU Protection Unit Data/Unified Region 2 + mcr p15, 0, r0, c6, c5, 0 @ PU Protection Unit Data/Unified Region 5 + + mrc p15, 0, r0, c9, c1, 0 @ DTCM + mov r0, r0, lsr #12 @ base + mov r0, r0, lsl #12 @ size + add r0, r0, #0x4000 @ dtcm top + + sub r0, r0, #4 @ irq vector + mov r1, #0 + str r1, [r0] + sub r0, r0, #4 @ IRQ1 Check Bits + str r1, [r0] + + sub r0, r0, #128 + bic r0, r0, #7 + + msr cpsr_c, #0xd3 @ svc mode + mov sp, r0 + sub r0, r0, #128 + msr cpsr_c, #0xd2 @ irq mode + mov sp, r0 + sub r0, r0, #128 + msr cpsr_c, #0xdf @ system mode + mov sp, r0 + + @ enable cache & tcm + mrc p15, 0, r0, c1, c0, 0 + ldr r1,= ITCM_ENABLE | DTCM_ENABLE | ICACHE_ENABLE | DCACHE_ENABLE + orr r0,r0,r1 + mcr p15, 0, r0, c1, c0, 0 + + ldr r10, =0x2FFFE04 + ldr r0, =0xE59FF018 + str r0, [r10] + add r1, r10, #0x20 + str r10, [r1] + bx r10 + + .pool + +mpu_initial_data: + .word 0x00000042 @ p15,0,c2,c0,0..1,r0 ;PU Cachability Bits for Data/Unified+Instruction Protection Region + .word 0x00000002 @ p15,0,c3,c0,0,r1 ;PU Write-Bufferability Bits for Data Protection Regions + .word 0x15111011 @ p15,0,c5,c0,2,r2 ;PU Extended Access Permission Data/Unified Protection Region + .word 0x05100011 @ p15,0,c5,c0,3,r3 ;PU Extended Access Permission Instruction Protection Region + .word 0x04000033 @ p15,0,c6,c0,0,r4 ;PU Protection Unit Data/Unified Region 0 + .word 0x0200002b @ p15,0,c6,c1,0,r5 ;PU Protection Unit Data/Unified Region 1 4MB + .word 0x08000035 @ p15,0,c6,c3,0,r6 ;PU Protection Unit Data/Unified Region 3 + .word 0x0300001b @ p15,0,c6,c4,0,r7 ;PU Protection Unit Data/Unified Region 4 + .word 0xffff001d @ p15,0,c6,c6,0,r8 ;PU Protection Unit Data/Unified Region 6 + .word 0x02fff017 @ p15,0,c6,c7,0,r9 ;PU Protection Unit Data/Unified Region 7 4KB + .word 0x0300000a @ p15,0,c9,c1,0,r10 ;TCM Data TCM Base and Virtual Size diff --git a/bootloader/load.ld b/bootloader/load.ld new file mode 100644 index 0000000..53f3728 --- /dev/null +++ b/bootloader/load.ld @@ -0,0 +1,198 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +MEMORY { + + vram : ORIGIN = 0x06000000, LENGTH = 128K +} + +__vram_start = ORIGIN(vram); +__vram_top = ORIGIN(vram)+ LENGTH(vram); +__sp_irq = __vram_top - 0x60; +__sp_svc = __sp_irq - 0x100; +__sp_usr = __sp_svc - 0x100; + +__irq_flags = __vram_top - 8; +__irq_vector = __vram_top - 4; + +SECTIONS +{ + .init : + { + __text_start = . ; + KEEP (*(.init)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .plt : + { + *(.plt) + } >vram = 0xff + + .text : /* ALIGN (4): */ + { + + *(.text*) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .fini : + { + KEEP (*(.fini)) + } >vram =0xff + + __text_end = . ; + + .rodata : + { + *(.rodata) + *all.rodata*(*) + *(.roda) + *(.rodata.*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >vram + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >vram + __exidx_end = .; + +/* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } >vram = 0xff + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } >vram = 0xff + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } >vram = 0xff + PROVIDE (__fini_array_end = .); + + .ctors : + { + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .eh_frame : + { + KEEP (*(.eh_frame)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram = 0xff + .jcr : { KEEP (*(.jcr)) } >vram = 0 + .got : { *(.got.plt) *(.got) } >vram = 0 + + + .vram ALIGN(4) : + { + __vram_start = ABSOLUTE(.) ; + *(.vram) + *vram.*(.text) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + __vram_end = ABSOLUTE(.) ; + } >vram = 0xff + + + .data ALIGN(4) : { + __data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); + __data_end = ABSOLUTE(.) ; + } >vram = 0xff + + + + .bss ALIGN(4) : + { + __bss_start = ABSOLUTE(.); + __bss_start__ = ABSOLUTE(.); + *(.dynbss) + *(.gnu.linkonce.b*) + *(.bss*) + *(COMMON) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >vram + + __bss_end = . ; + __bss_end__ = . ; + + _end = . ; + __end__ = . ; + PROVIDE (end = _end); + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .stack 0x80000 : { _stack = .; *(.stack) } + /* These must appear regardless of . */ +} diff --git a/bootloader/source/arm7clear.s b/bootloader/source/arm7clear.s new file mode 100644 index 0000000..52343e3 --- /dev/null +++ b/bootloader/source/arm7clear.s @@ -0,0 +1,70 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + + .arm + .global arm7clearRAM + .type arm7clearRAM STT_FUNC +arm7clearRAM: + + push {r0-r9} + // clear exclusive IWRAM + // 0380:0000 to 0380:FFFF, total 64KiB + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov r4, #0 + mov r5, #0 + mov r6, #0 + mov r7, #0 + mov r8, #0x03800000 + sub r8, #0x00008000 + mov r9, #0x03800000 + orr r9, r9, #0x10000 +clear_IWRAM_loop: + stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7} + cmp r8, r9 + blt clear_IWRAM_loop + + // clear most of EWRAM - except after RAM end - 0xc000, which has the bootstub + mov r8, #0x02000000 + + ldr r9,=0x4004008 + ldr r9,[r9] + ands r9,r9,#0x8000 + bne dsi_mode + + mov r9, #0x02400000 + b ds_mode +dsi_mode: + mov r9, #0x03000000 +ds_mode: + sub r9, #0x0000c000 +clear_EWRAM_loop: + stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7} + cmp r8, r9 + blt clear_EWRAM_loop + + pop {r0-r9} + + bx lr + diff --git a/bootloader/source/arm9clear.arm.c b/bootloader/source/arm9clear.arm.c new file mode 100644 index 0000000..b212da3 --- /dev/null +++ b/bootloader/source/arm9clear.arm.c @@ -0,0 +1,112 @@ +#define ARM9 +#undef ARM7 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "boot.h" + +/*------------------------------------------------------------------------- +resetMemory2_ARM9 +Clears the ARM9's DMA channels and resets video memory +Written by Darkain. +Modified by Chishm: + * Changed MultiNDS specific stuff +--------------------------------------------------------------------------*/ +void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9 (void) +{ + register int i; + + //clear out ARM9 DMA channels + for (i=0; i<4; i++) { + DMA_CR(i) = 0; + DMA_SRC(i) = 0; + DMA_DEST(i) = 0; + TIMER_CR(i) = 0; + TIMER_DATA(i) = 0; + } + + VRAM_CR = (VRAM_CR & 0xffff0000) | 0x00008080 ; + + u16 *mainregs = (u16*)0x04000000; + u16 *subregs = (u16*)0x04001000; + + for (i=0; i<43; i++) { + mainregs[i] = 0; + subregs[i] = 0; + } + + REG_DISPSTAT = 0; + + VRAM_A_CR = 0; + VRAM_B_CR = 0; +// Don't mess with the ARM7's VRAM +// VRAM_C_CR = 0; + VRAM_D_CR = 0; + VRAM_E_CR = 0; + VRAM_F_CR = 0; + VRAM_G_CR = 0; + VRAM_H_CR = 0; + VRAM_I_CR = 0; + REG_POWERCNT = 0x820F; + + //set shared ram to ARM7 + WRAM_CR = 0x03; + + // Return to passme loop + *((vu32*)0x02FFFE04) = (u32)0xE59FF018; // ldr pc, 0x02FFFE24 + *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; // Set ARM9 Loop address + + asm volatile( + "\tbx %0\n" + : : "r" (0x02FFFE04) + ); + while(1); +} + +void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) clearMasterBright_ARM9 (void) +{ + u16 mode = 1 << 14; + + *(u16*)(0x0400006C + (0x1000 * 0)) = 0 + mode; + *(u16*)(0x0400006C + (0x1000 * 1)) = 0 + mode; + + // Return to passme loop + *((vu32*)0x02FFFE04) = (u32)0xE59FF018; // ldr pc, 0x02FFFE24 + *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; // Set ARM9 Loop address + + asm volatile( + "\tbx %0\n" + : : "r" (0x02FFFE04) + ); + while(1); +} + +/*------------------------------------------------------------------------- +startBinary_ARM9 +Jumps to the ARM9 NDS binary in sync with the display and ARM7 +Written by Darkain. +Modified by Chishm: + * Removed MultiNDS specific stuff +--------------------------------------------------------------------------*/ +void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) startBinary_ARM9 (void) +{ + REG_IME=0; + REG_EXMEMCNT = 0xE880; + // set ARM9 load address to 0 and wait for it to change again + ARM9_START_FLAG = 0; + while(REG_VCOUNT!=191); + while(REG_VCOUNT==191); + while ( ARM9_START_FLAG != 1 ); + VoidFn arm9code = *(VoidFn*)(0x2FFFE24); + arm9code(); + while(1); +} + diff --git a/bootloader/source/arm9mpu_reset.s b/bootloader/source/arm9mpu_reset.s new file mode 100644 index 0000000..bbd10f0 --- /dev/null +++ b/bootloader/source/arm9mpu_reset.s @@ -0,0 +1,6 @@ + .arm + .global mpu_reset, mpu_reset_end + +mpu_reset: + .incbin "mpu_reset.bin" +mpu_reset_end: diff --git a/bootloader/source/bios.s b/bootloader/source/bios.s new file mode 100644 index 0000000..e98f57c --- /dev/null +++ b/bootloader/source/bios.s @@ -0,0 +1,13 @@ + .text + .align 4 + + .thumb + +@--------------------------------------------------------------------------------- + .global swiDelay + .thumb_func +@--------------------------------------------------------------------------------- +swiDelay: +@--------------------------------------------------------------------------------- + swi 0x03 + bx lr diff --git a/bootloader/source/boot.c b/bootloader/source/boot.c new file mode 100644 index 0000000..93c69a5 --- /dev/null +++ b/bootloader/source/boot.c @@ -0,0 +1,314 @@ +/*----------------------------------------------------------------- + boot.c + + BootLoader + Loads a file into memory and runs it + + All resetMemory and startBinary functions are based + on the MultiNDS loader by Darkain. + Original source available at: + http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp + +License: + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com + +Helpful information: + This code runs from VRAM bank C on ARM7 +------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#define ARM9 +#undef ARM7 +#include +#include +#include +#undef ARM9 +#define ARM7 +#include + +#include "fat.h" +#include "dldi_patcher.h" +#include "card.h" +#include "boot.h" + +void arm7clearRAM(); +int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out); +int sdmmc_sdcard_init(); +void sdmmc_controller_init(); + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Important things +#define TEMP_MEM 0x02FFE000 +#define NDS_HEAD 0x02FFFE00 +#define TEMP_ARM9_START_ADDRESS (*(vu32*)0x02FFFFF4) + + +const char* bootName = "BOOT.NDS"; + +extern unsigned long _start; +extern unsigned long storedFileCluster; +extern unsigned long initDisc; +extern unsigned long wantToPatchDLDI; +extern unsigned long argStart; +extern unsigned long argSize; +extern unsigned long dsiSD; + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Firmware stuff + +#define FW_READ 0x03 + +void boot_readFirmware (uint32 address, uint8 * buffer, uint32 size) { + uint32 index; + + // Read command + while (REG_SPICNT & SPI_BUSY); + REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM; + REG_SPIDATA = FW_READ; + while (REG_SPICNT & SPI_BUSY); + + // Set the address + REG_SPIDATA = (address>>16) & 0xFF; + while (REG_SPICNT & SPI_BUSY); + REG_SPIDATA = (address>>8) & 0xFF; + while (REG_SPICNT & SPI_BUSY); + REG_SPIDATA = (address) & 0xFF; + while (REG_SPICNT & SPI_BUSY); + + for (index = 0; index < size; index++) { + REG_SPIDATA = 0; + while (REG_SPICNT & SPI_BUSY); + buffer[index] = REG_SPIDATA & 0xFF; + } + REG_SPICNT = 0; +} + + +static inline void copyLoop (u32* dest, const u32* src, u32 size) { + size = (size +3) & ~3; + do { + *dest++ = *src++; + } while (size -= 4); +} + +//#define resetCpu() __asm volatile("\tswi 0x000000\n"); + +/*------------------------------------------------------------------------- +passArgs_ARM7 +Copies the command line arguments to the end of the ARM9 binary, +then sets a flag in memory for the loaded NDS to use +--------------------------------------------------------------------------*/ +void passArgs_ARM7 (void) { + u32 ARM9_DST = *((u32*)(NDS_HEAD + 0x028)); + u32 ARM9_LEN = *((u32*)(NDS_HEAD + 0x02C)); + u32* argSrc; + u32* argDst; + + if (!argStart || !argSize) return; + + argSrc = (u32*)(argStart + (int)&_start); + + argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned + + copyLoop(argDst, argSrc, argSize); + + __system_argv->argvMagic = ARGV_MAGIC; + __system_argv->commandLine = (char*)argDst; + __system_argv->length = argSize; +} + + + + +/*------------------------------------------------------------------------- +resetMemory_ARM7 +Clears all of the NDS's RAM that is visible to the ARM7 +Written by Darkain. +Modified by Chishm: + * Added STMIA clear mem loop +--------------------------------------------------------------------------*/ +void resetMemory_ARM7 (void) +{ + int i; + u8 settings1, settings2; + u32 settingsOffset = 0; + + REG_IME = 0; + + for (i=0; i<16; i++) { + SCHANNEL_CR(i) = 0; + SCHANNEL_TIMER(i) = 0; + SCHANNEL_SOURCE(i) = 0; + SCHANNEL_LENGTH(i) = 0; + } + + REG_SOUNDCNT = 0; + + //clear out ARM7 DMA channels and timers + for (i=0; i<4; i++) { + DMA_CR(i) = 0; + DMA_SRC(i) = 0; + DMA_DEST(i) = 0; + TIMER_CR(i) = 0; + TIMER_DATA(i) = 0; + } + + arm7clearRAM(); + + REG_IE = 0; + REG_IF = ~0; + (*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version + (*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version + REG_POWERCNT = 1; //turn off power to stuff + + // Get settings location + boot_readFirmware((u32)0x00020, (u8*)&settingsOffset, 0x2); + settingsOffset *= 8; + + // Reload DS Firmware settings + boot_readFirmware(settingsOffset + 0x070, &settings1, 0x1); + boot_readFirmware(settingsOffset + 0x170, &settings2, 0x1); + + if ((settings1 & 0x7F) == ((settings2+1) & 0x7F)) { + boot_readFirmware(settingsOffset + 0x000, (u8*)0x02FFFC80, 0x70); + } else { + boot_readFirmware(settingsOffset + 0x100, (u8*)0x02FFFC80, 0x70); + } +} + + +void loadBinary_ARM7 (u32 fileCluster) +{ + u32 ndsHeader[0x170>>2]; + + // read NDS header + fileRead ((char*)ndsHeader, fileCluster, 0, 0x170); + // read ARM9 info from NDS header + u32 ARM9_SRC = ndsHeader[0x020>>2]; + char* ARM9_DST = (char*)ndsHeader[0x028>>2]; + u32 ARM9_LEN = ndsHeader[0x02C>>2]; + // read ARM7 info from NDS header + u32 ARM7_SRC = ndsHeader[0x030>>2]; + char* ARM7_DST = (char*)ndsHeader[0x038>>2]; + u32 ARM7_LEN = ndsHeader[0x03C>>2]; + + // Load binaries into memory + fileRead(ARM9_DST, fileCluster, ARM9_SRC, ARM9_LEN); + fileRead(ARM7_DST, fileCluster, ARM7_SRC, ARM7_LEN); + + // first copy the header to its proper location, excluding + // the ARM9 start address, so as not to start it + TEMP_ARM9_START_ADDRESS = ndsHeader[0x024>>2]; // Store for later + ndsHeader[0x024>>2] = 0; + dmaCopyWords(3, (void*)ndsHeader, (void*)NDS_HEAD, 0x170); +} + +/*------------------------------------------------------------------------- +startBinary_ARM7 +Jumps to the ARM7 NDS binary in sync with the display and ARM9 +Written by Darkain. +Modified by Chishm: + * Removed MultiNDS specific stuff +--------------------------------------------------------------------------*/ +void startBinary_ARM7 (void) { + REG_IME=0; + while(REG_VCOUNT!=191); + while(REG_VCOUNT==191); + // copy NDS ARM9 start address into the header, starting ARM9 + *((vu32*)0x02FFFE24) = TEMP_ARM9_START_ADDRESS; + ARM9_START_FLAG = 1; + // Start ARM7 + VoidFn arm7code = *(VoidFn*)(0x2FFFE34); + arm7code(); +} + +int sdmmc_sd_readsectors(u32 sector_no, u32 numsectors, void *out); +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Main function +bool sdmmc_inserted() { + return true; +} + +bool sdmmc_startup() { + sdmmc_controller_init(); + return sdmmc_sdcard_init() == 0; +} + +bool sdmmc_readsectors(u32 sector_no, u32 numsectors, void *out) { + return sdmmc_sdcard_readsectors(sector_no, numsectors, out) == 0; +} + +int main (void) { + if (dsiSD) { + _io_dldi.fn_readSectors = sdmmc_readsectors; + _io_dldi.fn_isInserted = sdmmc_inserted; + _io_dldi.fn_startup = sdmmc_startup; + } + + u32 fileCluster = storedFileCluster; + // Init card + if(!FAT_InitFiles(initDisc)) + { + return -1; + } + if ((fileCluster < CLUSTER_FIRST) || (fileCluster >= CLUSTER_EOF)) /* Invalid file cluster specified */ + { + fileCluster = getBootFileCluster(bootName); + } + if (fileCluster == CLUSTER_FREE) + { + return -1; + } + + // ARM9 clears its memory part 2 + // copy ARM9 function to RAM, and make the ARM9 jump to it + copyLoop((void*)TEMP_MEM, (void*)resetMemory2_ARM9, resetMemory2_ARM9_size); + (*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function + // Wait until the ARM9 has completed its task + while ((*(vu32*)0x02FFFE24) == (u32)TEMP_MEM); + + // Get ARM7 to clear RAM + resetMemory_ARM7(); + + // ARM9 enters a wait loop + // copy ARM9 function to RAM, and make the ARM9 jump to it + copyLoop((void*)TEMP_MEM, (void*)startBinary_ARM9, startBinary_ARM9_size); + (*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function + + // Load the NDS file + loadBinary_ARM7(fileCluster); + + // Patch with DLDI if desired + if (wantToPatchDLDI) { + dldiPatchBinary ((u8*)((u32*)NDS_HEAD)[0x0A], ((u32*)NDS_HEAD)[0x0B]); + } + + // Pass command line arguments to loaded program + passArgs_ARM7(); + + startBinary_ARM7(); + + return 0; +} + diff --git a/bootloader/source/boot.h b/bootloader/source/boot.h new file mode 100644 index 0000000..3bb312e --- /dev/null +++ b/bootloader/source/boot.h @@ -0,0 +1,12 @@ +#ifndef _BOOT_H_ +#define _BOOT_H_ + +#define resetMemory2_ARM9_size 0x400 +void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9(); +#define clearMasterBright_ARM9_size 0x200 +void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) clearMasterBright_ARM9(); +#define startBinary_ARM9_size 0x100 +void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) startBinary_ARM9 (); +#define ARM9_START_FLAG (*(vu8*)0x02FFFDFB) + +#endif // _BOOT_H_ diff --git a/bootloader/source/card.h b/bootloader/source/card.h new file mode 100644 index 0000000..cd6f6fb --- /dev/null +++ b/bootloader/source/card.h @@ -0,0 +1,45 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + +#ifndef CARD_H +#define CARD_H + +#include "disc_io.h" +#include "io_dldi.h" + +static inline bool CARD_StartUp (void) { + return _io_dldi.fn_startup(); +} + +static inline bool CARD_IsInserted (void) { + return _io_dldi.fn_isInserted(); +} + +static inline bool CARD_ReadSector (u32 sector, void *buffer) { + return _io_dldi.fn_readSectors(sector, 1, buffer); +} + +static inline bool CARD_ReadSectors (u32 sector, int count, void *buffer) { + return _io_dldi.fn_readSectors(sector, count, buffer); +} + +#endif // CARD_H diff --git a/bootloader/source/disc_io.h b/bootloader/source/disc_io.h new file mode 100644 index 0000000..29033b7 --- /dev/null +++ b/bootloader/source/disc_io.h @@ -0,0 +1,82 @@ +/* + disc_io.h + Interface template for low level disc functions. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 2006-07-11 - Chishm + * Original release + + 2006-07-16 - Chishm + * Renamed _CF_USE_DMA to _IO_USE_DMA + * Renamed _CF_ALLOW_UNALIGNED to _IO_ALLOW_UNALIGNED +*/ + +#ifndef _DISC_IO_H +#define _DISC_IO_H + +#include +#define BYTES_PER_SECTOR 512 + +//---------------------------------------------------------------------- +// Customisable features + +// Use DMA to read the card, remove this line to use normal reads/writes +// #define _IO_USE_DMA + +// Allow buffers not alligned to 16 bits when reading files. +// Note that this will slow down access speed, so only use if you have to. +// It is also incompatible with DMA +#define _IO_ALLOW_UNALIGNED + +#if defined _IO_USE_DMA && defined _IO_ALLOW_UNALIGNED + #error "You can't use both DMA and unaligned memory" +#endif + +#define FEATURE_MEDIUM_CANREAD 0x00000001 +#define FEATURE_MEDIUM_CANWRITE 0x00000002 +#define FEATURE_SLOT_GBA 0x00000010 +#define FEATURE_SLOT_NDS 0x00000020 + +typedef bool (* FN_MEDIUM_STARTUP)(void) ; +typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; +typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u32 numSectors, void* buffer) ; +typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u32 numSectors, const void* buffer) ; +typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; +typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; + +struct IO_INTERFACE_STRUCT { + unsigned long ioType ; + unsigned long features ; + FN_MEDIUM_STARTUP fn_startup ; + FN_MEDIUM_ISINSERTED fn_isInserted ; + FN_MEDIUM_READSECTORS fn_readSectors ; + FN_MEDIUM_WRITESECTORS fn_writeSectors ; + FN_MEDIUM_CLEARSTATUS fn_clearStatus ; + FN_MEDIUM_SHUTDOWN fn_shutdown ; +} ; + +typedef struct IO_INTERFACE_STRUCT IO_INTERFACE ; + +#endif // define _DISC_IO_H diff --git a/bootloader/source/dldi_patcher.c b/bootloader/source/dldi_patcher.c new file mode 100644 index 0000000..13656f7 --- /dev/null +++ b/bootloader/source/dldi_patcher.c @@ -0,0 +1,208 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ +#ifndef NO_DLDI +#include +#include +#include "dldi_patcher.h" + +#define FIX_ALL 0x01 +#define FIX_GLUE 0x02 +#define FIX_GOT 0x04 +#define FIX_BSS 0x08 + +enum DldiOffsets { + DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm" + DO_magicToken = 0x00, // 0xBF8DA5ED + DO_magicShortString = 0x04, // " Chishm" + DO_version = 0x0C, + DO_driverSize = 0x0D, + DO_fixSections = 0x0E, + DO_allocatedSpace = 0x0F, + + DO_friendlyName = 0x10, + + DO_text_start = 0x40, // Data start + DO_data_end = 0x44, // Data end + DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing + DO_glue_end = 0x4C, // Interworking glue end + DO_got_start = 0x50, // GOT start -- Needs address fixing + DO_got_end = 0x54, // GOT end + DO_bss_start = 0x58, // bss start -- Needs setting to zero + DO_bss_end = 0x5C, // bss end + + // IO_INTERFACE data + DO_ioType = 0x60, + DO_features = 0x64, + DO_startup = 0x68, + DO_isInserted = 0x6C, + DO_readSectors = 0x70, + DO_writeSectors = 0x74, + DO_clearStatus = 0x78, + DO_shutdown = 0x7C, + DO_code = 0x80 +}; + +static addr_t readAddr (data_t *mem, addr_t offset) { + return ((addr_t*)mem)[offset/sizeof(addr_t)]; +} + +static void writeAddr (data_t *mem, addr_t offset, addr_t value) { + ((addr_t*)mem)[offset/sizeof(addr_t)] = value; +} + + +static addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) { + const int* dataChunk = (const int*) data; + int searchChunk = ((const int*)search)[0]; + addr_t i; + addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int)); + + for ( i = 0; i < dataChunkEnd; i++) { + if (dataChunk[i] == searchChunk) { + if ((i*sizeof(int) + searchLen) > dataLen) { + return -1; + } + if (memcmp (&data[i*sizeof(int)], search, searchLen) == 0) { + return i*sizeof(int); + } + } + } + + return -1; +} + +static const data_t dldiMagicString[] = "\xED\xA5\x8D\xBF Chishm"; // Normal DLDI file +static const data_t dldiMagicLoaderString[] = "\xEE\xA5\x8D\xBF Chishm"; // Different to a normal DLDI file +#define DEVICE_TYPE_DLDI 0x49444C44 + +extern const u32 _io_dldi; + +bool dldiPatchBinary (data_t *binData, u32 binSize) { + + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + addr_t patchOffset; // Position of patch destination in the file + addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly + addr_t ddmemOffset; // Original offset used in the DLDI file + addr_t ddmemStart; // Start of range that offsets can be in the DLDI file + addr_t ddmemEnd; // End of range that offsets can be in the DLDI file + addr_t ddmemSize; // Size of range that offsets can be in the DLDI file + addr_t addrIter; + + data_t *pDH; + data_t *pAH; + + size_t dldiFileSize = 0; + + // Find the DLDI reserved space in the file + patchOffset = quickFind (binData, dldiMagicString, binSize, sizeof(dldiMagicLoaderString)); + + if (patchOffset < 0) { + // does not have a DLDI section + return false; + } + + pDH = (data_t*)(((u32*)(&_io_dldi)) - 24); + pAH = &(binData[patchOffset]); + + if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) { + // No DLDI patch + return false; + } + + if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) { + // Not enough space for patch + return false; + } + + dldiFileSize = 1 << pDH[DO_driverSize]; + + memOffset = readAddr (pAH, DO_text_start); + if (memOffset == 0) { + memOffset = readAddr (pAH, DO_startup) - DO_code; + } + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Remember how much space is actually reserved + pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; + // Copy the DLDI patch into the application + memcpy (pAH, pDH, dldiFileSize); + + // Fix the section pointers in the header + writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); + writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset); + writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset); + writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset); + writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset); + writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset); + writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset); + writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset); + writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset); + writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset); + writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset); + writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset); + writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset); + + // Put the correct DLDI magic string back into the DLDI header + memcpy (pAH, dldiMagicString, sizeof (dldiMagicString)); + + if (pDH[DO_fixSections] & FIX_ALL) { + // Search through and fix pointers within the data section of the file + for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_GLUE) { + // Search through and fix pointers within the glue section of the file + for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_GOT) { + // Search through and fix pointers within the Global Offset Table section of the file + for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) { + if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) { + writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } + + return true; +} +#endif \ No newline at end of file diff --git a/bootloader/source/dldi_patcher.h b/bootloader/source/dldi_patcher.h new file mode 100644 index 0000000..f54c531 --- /dev/null +++ b/bootloader/source/dldi_patcher.h @@ -0,0 +1,32 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + +#ifndef DLDI_PATCHER_H +#define DLDI_PATCHER_H + +#include + +typedef signed int addr_t; +typedef unsigned char data_t; +bool dldiPatchBinary (data_t *binData, u32 binSize); + +#endif // DLDI_PATCHER_H diff --git a/bootloader/source/fat.c b/bootloader/source/fat.c new file mode 100644 index 0000000..f405f75 --- /dev/null +++ b/bootloader/source/fat.c @@ -0,0 +1,585 @@ +/*----------------------------------------------------------------- + fat.c + + NDS MP + GBAMP NDS Firmware Hack Version 2.12 + An NDS aware firmware patch for the GBA Movie Player. + By Michael Chisholm (Chishm) + + Filesystem code based on GBAMP_CF.c by Chishm (me). + +License: + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + +#include "fat.h" +#include "card.h" + + +//--------------------------------------------------------------- +// FAT constants + +#define FILE_LAST 0x00 +#define FILE_FREE 0xE5 + +#define ATTRIB_ARCH 0x20 +#define ATTRIB_DIR 0x10 +#define ATTRIB_LFN 0x0F +#define ATTRIB_VOL 0x08 +#define ATTRIB_HID 0x02 +#define ATTRIB_SYS 0x04 +#define ATTRIB_RO 0x01 + +#define FAT16_ROOT_DIR_CLUSTER 0x00 + +// File Constants +#ifndef EOF +#define EOF -1 +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + + +//----------------------------------------------------------------- +// FAT constants +#define CLUSTER_EOF_16 0xFFFF + +#define ATTRIB_ARCH 0x20 +#define ATTRIB_DIR 0x10 +#define ATTRIB_LFN 0x0F +#define ATTRIB_VOL 0x08 +#define ATTRIB_HID 0x02 +#define ATTRIB_SYS 0x04 +#define ATTRIB_RO 0x01 + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Data Structures + +#define __PACKED __attribute__ ((__packed__)) + +// Boot Sector - must be packed +typedef struct +{ + u8 jmpBoot[3]; + u8 OEMName[8]; + // BIOS Parameter Block + u16 bytesPerSector; + u8 sectorsPerCluster; + u16 reservedSectors; + u8 numFATs; + u16 rootEntries; + u16 numSectorsSmall; + u8 mediaDesc; + u16 sectorsPerFAT; + u16 sectorsPerTrk; + u16 numHeads; + u32 numHiddenSectors; + u32 numSectors; + union // Different types of extended BIOS Parameter Block for FAT16 and FAT32 + { + struct + { + // Ext BIOS Parameter Block for FAT16 + u8 driveNumber; + u8 reserved1; + u8 extBootSig; + u32 volumeID; + u8 volumeLabel[11]; + u8 fileSysType[8]; + // Bootcode + u8 bootCode[448]; + } fat16; + struct + { + // FAT32 extended block + u32 sectorsPerFAT32; + u16 extFlags; + u16 fsVer; + u32 rootClus; + u16 fsInfo; + u16 bkBootSec; + u8 reserved[12]; + // Ext BIOS Parameter Block for FAT16 + u8 driveNumber; + u8 reserved1; + u8 extBootSig; + u32 volumeID; + u8 volumeLabel[11]; + u8 fileSysType[8]; + // Bootcode + u8 bootCode[420]; + } fat32; + } extBlock; + + __PACKED u16 bootSig; + +} __PACKED BOOT_SEC; + +// Directory entry - must be packed +typedef struct +{ + u8 name[8]; + u8 ext[3]; + u8 attrib; + u8 reserved; + u8 cTime_ms; + u16 cTime; + u16 cDate; + u16 aDate; + u16 startClusterHigh; + u16 mTime; + u16 mDate; + u16 startCluster; + u32 fileSize; +} __PACKED DIR_ENT; + +// File information - no need to pack +typedef struct +{ + u32 firstCluster; + u32 length; + u32 curPos; + u32 curClus; // Current cluster to read from + int curSect; // Current sector within cluster + int curByte; // Current byte within sector + char readBuffer[512]; // Buffer used for unaligned reads + u32 appClus; // Cluster to append to + int appSect; // Sector within cluster for appending + int appByte; // Byte within sector for appending + bool read; // Can read from file + bool write; // Can write to file + bool append;// Can append to file + bool inUse; // This file is open + u32 dirEntSector; // The sector where the directory entry is stored + int dirEntOffset; // The offset within the directory sector +} FAT_FILE; + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Global Variables + +// _VARS_IN_RAM variables are stored in the largest section of WRAM +// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA + +// Locations on card +int discRootDir; +int discRootDirClus; +int discFAT; +int discSecPerFAT; +int discNumSec; +int discData; +int discBytePerSec; +int discSecPerClus; +int discBytePerClus; + +enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} discFileSystem; + +// Global sector buffer to save on stack space +unsigned char globalBuffer[BYTES_PER_SECTOR]; + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//FAT routines + +u32 FAT_ClustToSect (u32 cluster) { + return (((cluster-2) * discSecPerClus) + discData); +} + +/*----------------------------------------------------------------- +FAT_NextCluster +Internal function - gets the cluster linked from input cluster +-----------------------------------------------------------------*/ +u32 FAT_NextCluster(u32 cluster) +{ + u32 nextCluster = CLUSTER_FREE; + u32 sector; + int offset; + + + switch (discFileSystem) + { + case FS_UNKNOWN: + nextCluster = CLUSTER_FREE; + break; + + case FS_FAT12: + sector = discFAT + (((cluster * 3) / 2) / BYTES_PER_SECTOR); + offset = ((cluster * 3) / 2) % BYTES_PER_SECTOR; + CARD_ReadSector(sector, globalBuffer); + nextCluster = ((u8*) globalBuffer)[offset]; + offset++; + + if (offset >= BYTES_PER_SECTOR) { + offset = 0; + sector++; + } + + CARD_ReadSector(sector, globalBuffer); + nextCluster |= (((u8*) globalBuffer)[offset]) << 8; + + if (cluster & 0x01) { + nextCluster = nextCluster >> 4; + } else { + nextCluster &= 0x0FFF; + } + + break; + + case FS_FAT16: + sector = discFAT + ((cluster << 1) / BYTES_PER_SECTOR); + offset = cluster % (BYTES_PER_SECTOR >> 1); + + CARD_ReadSector(sector, globalBuffer); + // read the nextCluster value + nextCluster = ((u16*)globalBuffer)[offset]; + + if (nextCluster >= 0xFFF7) + { + nextCluster = CLUSTER_EOF; + } + break; + + case FS_FAT32: + sector = discFAT + ((cluster << 2) / BYTES_PER_SECTOR); + offset = cluster % (BYTES_PER_SECTOR >> 2); + + CARD_ReadSector(sector, globalBuffer); + // read the nextCluster value + nextCluster = (((u32*)globalBuffer)[offset]) & 0x0FFFFFFF; + + if (nextCluster >= 0x0FFFFFF7) + { + nextCluster = CLUSTER_EOF; + } + break; + + default: + nextCluster = CLUSTER_FREE; + break; + } + + return nextCluster; +} + +/*----------------------------------------------------------------- +ucase +Returns the uppercase version of the given char +char IN: a character +char return OUT: uppercase version of character +-----------------------------------------------------------------*/ +char ucase (char character) +{ + if ((character > 0x60) && (character < 0x7B)) + character = character - 0x20; + return (character); +} + +/*----------------------------------------------------------------- +FAT_InitFiles +Reads the FAT information from the CF card. +You need to call this before reading any files. +bool return OUT: true if successful. +-----------------------------------------------------------------*/ +bool FAT_InitFiles (bool initCard) +{ + int i; + int bootSector; + BOOT_SEC* bootSec; + + if (initCard && !CARD_StartUp()) + { + return (false); + } + + // Read first sector of card + if (!CARD_ReadSector (0, globalBuffer)) + { + return false; + } + // Check if there is a FAT string, which indicates this is a boot sector + if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T')) + { + bootSector = 0; + } + // Check for FAT32 + else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T')) + { + bootSector = 0; + } + else // This is an MBR + { + // Find first valid partition from MBR + // First check for an active partition + for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10); + // If it didn't find an active partition, search for any valid partition + if (i == 0x1FE) + for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10); + + // Go to first valid partition + if ( i != 0x1FE) // Make sure it found a partition + { + bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F); + } else { + bootSector = 0; // No partition found, assume this is a MBR free disk + } + } + + // Read in boot sector + bootSec = (BOOT_SEC*) globalBuffer; + CARD_ReadSector (bootSector, bootSec); + + // Store required information about the file system + if (bootSec->sectorsPerFAT != 0) + { + discSecPerFAT = bootSec->sectorsPerFAT; + } + else + { + discSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32; + } + + if (bootSec->numSectorsSmall != 0) + { + discNumSec = bootSec->numSectorsSmall; + } + else + { + discNumSec = bootSec->numSectors; + } + + discBytePerSec = BYTES_PER_SECTOR; // Sector size is redefined to be 512 bytes + discSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTES_PER_SECTOR; + discBytePerClus = discBytePerSec * discSecPerClus; + discFAT = bootSector + bootSec->reservedSectors; + + discRootDir = discFAT + (bootSec->numFATs * discSecPerFAT); + discData = discRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / BYTES_PER_SECTOR); + + if ((discNumSec - discData) / bootSec->sectorsPerCluster < 4085) + { + discFileSystem = FS_FAT12; + } + else if ((discNumSec - discData) / bootSec->sectorsPerCluster < 65525) + { + discFileSystem = FS_FAT16; + } + else + { + discFileSystem = FS_FAT32; + } + + if (discFileSystem != FS_FAT32) + { + discRootDirClus = FAT16_ROOT_DIR_CLUSTER; + } + else // Set up for the FAT32 way + { + discRootDirClus = bootSec->extBlock.fat32.rootClus; + // Check if FAT mirroring is enabled + if (!(bootSec->extBlock.fat32.extFlags & 0x80)) + { + // Use the active FAT + discFAT = discFAT + ( discSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F)); + } + } + + return (true); +} + + +/*----------------------------------------------------------------- +getBootFileCluster +-----------------------------------------------------------------*/ +u32 getBootFileCluster (const char* bootName) +{ + DIR_ENT dir; + int firstSector = 0; + bool notFound = false; + bool found = false; +// int maxSectors; + u32 wrkDirCluster = discRootDirClus; + u32 wrkDirSector = 0; + int wrkDirOffset = 0; + int nameOffset; + + dir.startCluster = CLUSTER_FREE; // default to no file found + dir.startClusterHigh = CLUSTER_FREE; + + + // Check if fat has been initialised + if (discBytePerSec == 0) + { + return (CLUSTER_FREE); + } + + char *ptr = (char*)bootName; + while (*ptr != '.') ptr++; + int namelen = ptr - bootName; + +// maxSectors = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? (discData - discRootDir) : discSecPerClus); + // Scan Dir for correct entry + firstSector = discRootDir; + CARD_ReadSector (firstSector + wrkDirSector, globalBuffer); + found = false; + notFound = false; + wrkDirOffset = -1; // Start at entry zero, Compensating for increment + while (!found && !notFound) { + wrkDirOffset++; + if (wrkDirOffset == BYTES_PER_SECTOR / sizeof (DIR_ENT)) + { + wrkDirOffset = 0; + wrkDirSector++; + if ((wrkDirSector == discSecPerClus) && (wrkDirCluster != FAT16_ROOT_DIR_CLUSTER)) + { + wrkDirSector = 0; + wrkDirCluster = FAT_NextCluster(wrkDirCluster); + if (wrkDirCluster == CLUSTER_EOF) + { + notFound = true; + } + firstSector = FAT_ClustToSect(wrkDirCluster); + } + else if ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER) && (wrkDirSector == (discData - discRootDir))) + { + notFound = true; // Got to end of root dir + } + CARD_ReadSector (firstSector + wrkDirSector, globalBuffer); + } + dir = ((DIR_ENT*) globalBuffer)[wrkDirOffset]; + found = true; + if ((dir.attrib & ATTRIB_DIR) || (dir.attrib & ATTRIB_VOL)) + { + found = false; + } + if(namelen<8 && dir.name[namelen]!=0x20) found = false; + for (nameOffset = 0; nameOffset < namelen && found; nameOffset++) + { + if (ucase(dir.name[nameOffset]) != bootName[nameOffset]) + found = false; + } + for (nameOffset = 0; nameOffset < 3 && found; nameOffset++) + { + if (ucase(dir.ext[nameOffset]) != bootName[nameOffset+namelen+1]) + found = false; + } + if (dir.name[0] == FILE_LAST) + { + notFound = true; + } + } + + // If no file is found, return CLUSTER_FREE + if (notFound) + { + return CLUSTER_FREE; + } + + return (dir.startCluster | (dir.startClusterHigh << 16)); +} + +/*----------------------------------------------------------------- +fileRead(buffer, cluster, startOffset, length) +-----------------------------------------------------------------*/ +u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length) +{ + int curByte; + int curSect; + + int dataPos = 0; + int chunks; + int beginBytes; + + if (cluster == CLUSTER_FREE || cluster == CLUSTER_EOF) + { + return 0; + } + + // Follow cluster list until desired one is found + for (chunks = startOffset / discBytePerClus; chunks > 0; chunks--) + { + cluster = FAT_NextCluster (cluster); + } + + // Calculate the sector and byte of the current position, + // and store them + curSect = (startOffset % discBytePerClus) / BYTES_PER_SECTOR; + curByte = startOffset % BYTES_PER_SECTOR; + + // Load sector buffer for new position in file + CARD_ReadSector( curSect + FAT_ClustToSect(cluster), globalBuffer); + curSect++; + + // Number of bytes needed to read to align with a sector + beginBytes = (BYTES_PER_SECTOR < length + curByte ? (BYTES_PER_SECTOR - curByte) : length); + + // Read first part from buffer, to align with sector boundary + for (dataPos = 0 ; dataPos < beginBytes; dataPos++) + { + buffer[dataPos] = globalBuffer[curByte++]; + } + + // Read in all the 512 byte chunks of the file directly, saving time + for ( chunks = ((int)length - beginBytes) / BYTES_PER_SECTOR; chunks > 0;) + { + int sectorsToRead; + + // Move to the next cluster if necessary + if (curSect >= discSecPerClus) + { + curSect = 0; + cluster = FAT_NextCluster (cluster); + } + + // Calculate how many sectors to read (read a maximum of discSecPerClus at a time) + sectorsToRead = discSecPerClus - curSect; + if(chunks < sectorsToRead) + sectorsToRead = chunks; + + // Read the sectors + CARD_ReadSectors(curSect + FAT_ClustToSect(cluster), sectorsToRead, buffer + dataPos); + chunks -= sectorsToRead; + curSect += sectorsToRead; + dataPos += BYTES_PER_SECTOR * sectorsToRead; + } + + // Take care of any bytes left over before end of read + if (dataPos < length) + { + + // Update the read buffer + curByte = 0; + if (curSect >= discSecPerClus) + { + curSect = 0; + cluster = FAT_NextCluster (cluster); + } + CARD_ReadSector( curSect + FAT_ClustToSect( cluster), globalBuffer); + + // Read in last partial chunk + for (; dataPos < length; dataPos++) + { + buffer[dataPos] = globalBuffer[curByte]; + curByte++; + } + } + + return dataPos; +} diff --git a/bootloader/source/fat.h b/bootloader/source/fat.h new file mode 100644 index 0000000..d39076b --- /dev/null +++ b/bootloader/source/fat.h @@ -0,0 +1,46 @@ +/*----------------------------------------------------------------- + fat.h + + NDS MP + GBAMP NDS Firmware Hack Version 2.12 + An NDS aware firmware patch for the GBA Movie Player. + By Michael Chisholm (Chishm) + + Filesystem code based on GBAMP_CF.c by Chishm (me). + +License: + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + +#ifndef FAT_H +#define FAT_H + +#include + +#define CLUSTER_FREE 0x00000000 +#define CLUSTER_EOF 0x0FFFFFFF +#define CLUSTER_FIRST 0x00000002 + +bool FAT_InitFiles (bool initCard); +u32 getBootFileCluster (const char* bootName); +u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length); +u32 FAT_ClustToSect (u32 cluster); + +#endif // FAT_H diff --git a/bootloader/source/io_dldi.h b/bootloader/source/io_dldi.h new file mode 100644 index 0000000..e0f4efa --- /dev/null +++ b/bootloader/source/io_dldi.h @@ -0,0 +1,44 @@ +/* + io_dldi.h + + Reserved space for post-compilation adding of an extra driver + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 2006-12-22 - Chishm + * Original release +*/ + +#ifndef IO_DLDI_H +#define IO_DLDI_H + +// 'DLDD' +#define DEVICE_TYPE_DLDD 0x49444C44 + +#include "disc_io.h" + +// export interface +extern IO_INTERFACE _io_dldi ; + +#endif // define IO_DLDI_H diff --git a/bootloader/source/io_dldi.s b/bootloader/source/io_dldi.s new file mode 100644 index 0000000..fdfbde1 --- /dev/null +++ b/bootloader/source/io_dldi.s @@ -0,0 +1,124 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ +@--------------------------------------------------------------------------------- + .align 4 + .arm + .global _dldi_start + .global _io_dldi +@--------------------------------------------------------------------------------- +.equ FEATURE_MEDIUM_CANREAD, 0x00000001 +.equ FEATURE_MEDIUM_CANWRITE, 0x00000002 +.equ FEATURE_SLOT_GBA, 0x00000010 +.equ FEATURE_SLOT_NDS, 0x00000020 + + +_dldi_start: +#ifndef NO_DLDI + +@--------------------------------------------------------------------------------- +@ Driver patch file standard header -- 16 bytes +#ifdef STANDARD_DLDI + .word 0xBF8DA5ED @ Magic number to identify this region +#else + .word 0xBF8DA5EE @ Magic number to identify this region +#endif + .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) + .byte 0x01 @ Version number + .byte 0x0e @ 16KiB @ Log [base-2] of the size of this driver in bytes. + .byte 0x00 @ Sections to fix + .byte 0x0e @ 16KiB @ Log [base-2] of the allocated space in bytes. + +@--------------------------------------------------------------------------------- +@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes + .align 4 + .asciz "Loader (No interface)" + +@--------------------------------------------------------------------------------- +@ Offsets to important sections within the data -- 32 bytes + .align 6 + .word _dldi_start @ data start + .word _dldi_end @ data end + .word 0x00000000 @ Interworking glue start -- Needs address fixing + .word 0x00000000 @ Interworking glue end + .word 0x00000000 @ GOT start -- Needs address fixing + .word 0x00000000 @ GOT end + .word 0x00000000 @ bss start -- Needs setting to zero + .word 0x00000000 @ bss end +@--------------------------------------------------------------------------------- +@ IO_INTERFACE data -- 32 bytes +_io_dldi: + .ascii "DLDI" @ ioType + .word 0x00000000 @ Features + .word _DLDI_startup @ + .word _DLDI_isInserted @ + .word _DLDI_readSectors @ Function pointers to standard device driver functions + .word _DLDI_writeSectors @ + .word _DLDI_clearStatus @ + .word _DLDI_shutdown @ + + +@--------------------------------------------------------------------------------- + +_DLDI_startup: +_DLDI_isInserted: +_DLDI_readSectors: +_DLDI_writeSectors: +_DLDI_clearStatus: +_DLDI_shutdown: + mov r0, #0x00 @ Return false for every function + bx lr + + + +@--------------------------------------------------------------------------------- + .align + .pool + + .space (_dldi_start + 16384) - . @ Fill to 16KiB + +_dldi_end: + .end +@--------------------------------------------------------------------------------- +#else +@--------------------------------------------------------------------------------- +@ IO_INTERFACE data -- 32 bytes +_io_dldi: + .ascii "DLDI" @ ioType + .word 0x00000000 @ Features + .word _DLDI_startup @ + .word _DLDI_isInserted @ + .word _DLDI_readSectors @ Function pointers to standard device driver functions + .word _DLDI_writeSectors @ + .word _DLDI_clearStatus @ + .word _DLDI_shutdown @ + + _DLDI_startup: +_DLDI_isInserted: +_DLDI_readSectors: +_DLDI_writeSectors: +_DLDI_clearStatus: +_DLDI_shutdown: + mov r0, #0x00 @ Return false for every function + bx lr + + +#endif diff --git a/bootloader/source/load_crt0.s b/bootloader/source/load_crt0.s new file mode 100644 index 0000000..ea7949b --- /dev/null +++ b/bootloader/source/load_crt0.s @@ -0,0 +1,144 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2005 Michael "Chishm" Chisholm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + If you use this code, please give due credit and email me about your + project at chishm@hotmail.com +------------------------------------------------------------------*/ + +@--------------------------------------------------------------------------------- + .section ".init" + .global _start + .global storedFileCluster + .global initDisc + .global wantToPatchDLDI + .global argStart + .global argSize + .global dsiSD +@--------------------------------------------------------------------------------- + .align 4 + .arm +@--------------------------------------------------------------------------------- +_start: +@--------------------------------------------------------------------------------- + b startUp + +storedFileCluster: + .word 0x0FFFFFFF @ default BOOT.NDS +initDisc: + .word 0x00000001 @ init the disc by default +wantToPatchDLDI: + .word 0x00000001 @ by default patch the DLDI section of the loaded NDS +@ Used for passing arguments to the loaded app +argStart: + .word _end - _start +argSize: + .word 0x00000000 +dldiOffset: + .word _dldi_start - _start +dsiSD: + .word 0 + +startUp: + mov r0, #0x04000000 + mov r1, #0 + str r1, [r0,#0x208] @ REG_IME + str r1, [r0,#0x210] @ REG_IE + str r1, [r0,#0x218] @ REG_AUXIE + + mov r0, #0x12 @ Switch to IRQ Mode + msr cpsr, r0 + ldr sp, =__sp_irq @ Set IRQ stack + + mov r0, #0x13 @ Switch to SVC Mode + msr cpsr, r0 + ldr sp, =__sp_svc @ Set SVC stack + + mov r0, #0x1F @ Switch to System Mode + msr cpsr, r0 + ldr sp, =__sp_usr @ Set user stack + + ldr r0, =__bss_start @ Clear BSS section to 0x00 + ldr r1, =__bss_end + sub r1, r1, r0 + bl ClearMem + + mov r0, #0 @ int argc + mov r1, #0 @ char *argv[] + ldr r3, =main + bl _blx_r3_stub @ jump to user code + + @ If the user ever returns, restart + b _start + +@--------------------------------------------------------------------------------- +_blx_r3_stub: +@--------------------------------------------------------------------------------- + bx r3 + +@--------------------------------------------------------------------------------- +@ Clear memory to 0x00 if length != 0 +@ r0 = Start Address +@ r1 = Length +@--------------------------------------------------------------------------------- +ClearMem: +@--------------------------------------------------------------------------------- + mov r2, #3 @ Round down to nearest word boundary + add r1, r1, r2 @ Shouldn't be needed + bics r1, r1, r2 @ Clear 2 LSB (and set Z) + bxeq lr @ Quit if copy size is 0 + + mov r2, #0 +ClrLoop: + stmia r0!, {r2} + subs r1, r1, #4 + bne ClrLoop + bx lr + +@--------------------------------------------------------------------------------- +@ Copy memory if length != 0 +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length +@--------------------------------------------------------------------------------- +CopyMemCheck: +@--------------------------------------------------------------------------------- + sub r3, r4, r2 @ Is there any data to copy? +@--------------------------------------------------------------------------------- +@ Copy memory +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length +@--------------------------------------------------------------------------------- +CopyMem: +@--------------------------------------------------------------------------------- + mov r0, #3 @ These commands are used in cases where + add r3, r3, r0 @ the length is not a multiple of 4, + bics r3, r3, r0 @ even though it should be. + bxeq lr @ Length is zero, so exit +CIDLoop: + ldmia r1!, {r0} + stmia r2!, {r0} + subs r3, r3, #4 + bne CIDLoop + bx lr + +@--------------------------------------------------------------------------------- + .align + .pool + .end +@--------------------------------------------------------------------------------- diff --git a/bootloader/source/sdmmc.c b/bootloader/source/sdmmc.c new file mode 100644 index 0000000..13ff139 --- /dev/null +++ b/bootloader/source/sdmmc.c @@ -0,0 +1,301 @@ +#ifndef NO_SDMMC +#include +#include +#include + +static struct mmcdevice deviceSD; + +//--------------------------------------------------------------------------------- +int geterror(struct mmcdevice *ctx) { +//--------------------------------------------------------------------------------- + //if(ctx->error == 0x4) return -1; + //else return 0; + return (ctx->error << 29) >> 31; +} + + +//--------------------------------------------------------------------------------- +void setTarget(struct mmcdevice *ctx) { +//--------------------------------------------------------------------------------- + sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber); + setckl(ctx->clk); + if (ctx->SDOPT == 0) { + sdmmc_mask16(REG_SDOPT, 0, 0x8000); + } else { + sdmmc_mask16(REG_SDOPT, 0x8000, 0); + } + +} + + +//--------------------------------------------------------------------------------- +void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) { +//--------------------------------------------------------------------------------- + int i; + bool getSDRESP = (cmd << 15) >> 31; + uint16_t flags = (cmd << 15) >> 31; + const bool readdata = cmd & 0x20000; + const bool writedata = cmd & 0x40000; + + if(readdata || writedata) + { + flags |= TMIO_STAT0_DATAEND; + } + + ctx->error = 0; + while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? + sdmmc_write16(REG_SDIRMASK0,0); + sdmmc_write16(REG_SDIRMASK1,0); + sdmmc_write16(REG_SDSTATUS0,0); + sdmmc_write16(REG_SDSTATUS1,0); +#ifdef DATA32_SUPPORT +// if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800); +// if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000); +// sdmmc_mask16(REG_DATACTL32,0x1800,2); +#else + sdmmc_mask16(REG_DATACTL32,0x1800,0); +#endif + sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); + sdmmc_write16(REG_SDCMDARG1,args >> 16); + sdmmc_write16(REG_SDCMD,cmd &0xFFFF); + + uint32_t size = ctx->size; + uint16_t *dataPtr = (uint16_t*)ctx->data; + uint32_t *dataPtr32 = (uint32_t*)ctx->data; + + bool useBuf = ( NULL != dataPtr ); + bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr)))); + + uint16_t status0 = 0; + + while(1) { + volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); +#ifdef DATA32_SUPPORT + volatile uint16_t ctl32 = sdmmc_read16(REG_SDDATACTL32); + if((ctl32 & 0x100)) +#else + if((status1 & TMIO_STAT1_RXRDY)) +#endif + { + if(readdata) { + if(useBuf) { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); + if(size > 0x1FF) { +#ifdef DATA32_SUPPORT + if(useBuf32) { + for(i = 0; i<0x200; i+=4) { + *dataPtr32++ = sdmmc_read32(REG_SDFIFO32); + } + } else { +#endif + for(i = 0; i<0x200; i+=2) { + *dataPtr++ = sdmmc_read16(REG_SDFIFO); + } +#ifdef DATA32_SUPPORT + } +#endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_SDDATACTL32, 0x800, 0); + } + } +#ifdef DATA32_SUPPORT + if(!(ctl32 & 0x200)) +#else + if((status1 & TMIO_STAT1_TXRQ)) +#endif + { + if(writedata) { + if(useBuf) { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); + //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); + if(size > 0x1FF) { +#ifdef DATA32_SUPPORT + for(i = 0; i<0x200; i+=4) { + sdmmc_write32(REG_SDFIFO32,*dataPtr32++); + } +#else + for(i = 0; i<0x200; i+=2) { + sdmmc_write16(REG_SDFIFO,*dataPtr++); + } +#endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_SDDATACTL32, 0x1000, 0); + } + } + if(status1 & TMIO_MASK_GW) { + ctx->error |= 4; + break; + } + + if(!(status1 & TMIO_STAT1_CMD_BUSY)) { + status0 = sdmmc_read16(REG_SDSTATUS0); + if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) { + ctx->error |= 0x1; + } + if(status0 & TMIO_STAT0_DATAEND) { + ctx->error |= 0x2; + } + + if((status0 & flags) == flags) + break; + } + } + ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); + ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); + sdmmc_write16(REG_SDSTATUS0,0); + sdmmc_write16(REG_SDSTATUS1,0); + + if(getSDRESP != 0) { + ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16); + ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16); + ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16); + ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16); + } +} + + +//--------------------------------------------------------------------------------- +int sdmmc_cardinserted() { +//--------------------------------------------------------------------------------- + return 1; //sdmmc_cardready; +} + +//--------------------------------------------------------------------------------- +void sdmmc_controller_init(bool force) { +//--------------------------------------------------------------------------------- + deviceSD.isSDHC = 0; + deviceSD.SDOPT = 0; + deviceSD.res = 0; + deviceSD.initarg = 0; + deviceSD.clk = 0x80; + deviceSD.devicenumber = 0; + + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xF7FFu; + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xEFFFu; +#ifdef DATA32_SUPPORT + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) |= 0x402u; +#else + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) |= 0x402u; +#endif + *(vu16*)(SDMMC_BASE + REG_SDDATACTL) = (*(vu16*)(SDMMC_BASE + REG_SDDATACTL) & 0xFFDD) | 2; +#ifdef DATA32_SUPPORT + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFFu; + *(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDFu; + *(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 512; +#else + *(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFDu; + *(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDDu; + *(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 0; +#endif + *(vu16*)(SDMMC_BASE + REG_SDBLKCOUNT32) = 1; + *(vu16*)(SDMMC_BASE + REG_SDRESET) &= 0xFFFEu; + *(vu16*)(SDMMC_BASE + REG_SDRESET) |= 1u; + *(vu16*)(SDMMC_BASE + REG_SDIRMASK0) |= TMIO_MASK_ALL; + *(vu16*)(SDMMC_BASE + REG_SDIRMASK1) |= TMIO_MASK_ALL>>16; + *(vu16*)(SDMMC_BASE + 0x0fc) |= 0xDBu; //SDCTL_RESERVED7 + *(vu16*)(SDMMC_BASE + 0x0fe) |= 0xDBu; //SDCTL_RESERVED8 + *(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu; +#ifdef DATA32_SUPPORT + *(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x20; + *(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EE; +#else + *(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x40; //Nintendo sets this to 0x20 + *(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EB; //Nintendo sets this to 0x40EE +#endif + *(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu; + *(vu16*)(SDMMC_BASE + REG_SDBLKLEN) = 512; + *(vu16*)(SDMMC_BASE + REG_SDSTOP) = 0; + + setTarget(&deviceSD); +} + +//--------------------------------------------------------------------------------- +int sdmmc_sdcard_init() { +//--------------------------------------------------------------------------------- + setTarget(&deviceSD); + swiDelay(0xF000); + sdmmc_send_command(&deviceSD,0,0); + sdmmc_send_command(&deviceSD,0x10408,0x1AA); + u32 temp = (deviceSD.error & 0x1) << 0x1E; + + u32 temp2 = 0; + do { + do { + sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); + sdmmc_send_command(&deviceSD,0x10769,0x00FF8000 | temp); + temp2 = 1; + } while ( !(deviceSD.error & 1) ); + + } while((deviceSD.ret[0] & 0x80000000) == 0); + + if(!((deviceSD.ret[0] >> 30) & 1) || !temp) + temp2 = 0; + + deviceSD.isSDHC = temp2; + + sdmmc_send_command(&deviceSD,0x10602,0); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x10403,0); + if (deviceSD.error & 0x4) return -1; + deviceSD.initarg = deviceSD.ret[0] >> 0x10; + + sdmmc_send_command(&deviceSD,0x10609,deviceSD.initarg << 0x10); + if (deviceSD.error & 0x4) return -1; + + deviceSD.clk = 1; + setckl(1); + + sdmmc_send_command(&deviceSD,0x10507,deviceSD.initarg << 0x10); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x1076A,0x0); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10); + if (deviceSD.error & 0x4) return -1; + + deviceSD.SDOPT = 1; + sdmmc_send_command(&deviceSD,0x10446,0x2); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x1040D,deviceSD.initarg << 0x10); + if (deviceSD.error & 0x4) return -1; + + sdmmc_send_command(&deviceSD,0x10410,0x200); + if (deviceSD.error & 0x4) return -1; + deviceSD.clk |= 0x200; + + return 0; + +} + +//--------------------------------------------------------------------------------- +int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out) { +//--------------------------------------------------------------------------------- + if (deviceSD.isSDHC == 0) + sector_no <<= 9; + setTarget(&deviceSD); + sdmmc_write16(REG_SDSTOP,0x100); + +#ifdef DATA32_SUPPORT + sdmmc_write16(REG_SDBLKCOUNT32,numsectors); + sdmmc_write16(REG_SDBLKLEN32,0x200); +#endif + + sdmmc_write16(REG_SDBLKCOUNT,numsectors); + deviceSD.data = out; + deviceSD.size = numsectors << 9; + sdmmc_send_command(&deviceSD,0x33C12,sector_no); + return geterror(&deviceSD); +} +#endif \ No newline at end of file diff --git a/bootstub/Makefile b/bootstub/Makefile new file mode 100644 index 0000000..aea4f55 --- /dev/null +++ b/bootstub/Makefile @@ -0,0 +1,13 @@ +include $(DEVKITARM)/base_tools + +TARGET := bootstub + +../data/$(TARGET).bin: $(TARGET).elf + $(OBJCOPY) -O binary $< $@ + +$(TARGET).elf: $(TARGET).s Makefile + $(CC) -Wl,-Ttext=0 -x assembler-with-cpp -nostartfiles -nostdlib $(TARGET).s -o $@ + + +clean: + rm -f $(TARGET).elf $(TARGET).bin diff --git a/bootstub/bootstub.s b/bootstub/bootstub.s new file mode 100644 index 0000000..579fb99 --- /dev/null +++ b/bootstub/bootstub.s @@ -0,0 +1,176 @@ +/*----------------------------------------------------------------- + + Copyright (C) 2010 Dave "WinterMute" Murphy + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +------------------------------------------------------------------*/ + .global _start + +//----------------------------------------------------------------- +_start: +//----------------------------------------------------------------- + .ascii "bootstub" + .word hook7from9 - _start + .word hook9from7 - _start +_loader_size: + .word 0 + + .arch armv4t + .cpu arm7tdmi + +//----------------------------------------------------------------- +hook9from7: +//----------------------------------------------------------------- + ldr r0, arm9bootaddr + adr r1, hook7from9 + str r1, [r0] + + mov r3, #0x04000000 + ldr r0, resetcode + str r0, [r3, #0x188] + add r3, r3, #0x180 + + adr r0, waitcode_start + ldr r1, arm7base + adr r2, waitcode_end +1: ldr r4, [r0],#4 + str r4, [r1],#4 + cmp r2, r0 + bne 1b + + ldr r1, arm7base + bx r1 + +//----------------------------------------------------------------- +waitcode_start: +//----------------------------------------------------------------- + push {lr} + mov r2, #1 + bl waitsync + + mov r0, #0x100 + strh r0, [r3] + + mov r2, #0 + bl waitsync + + mov r0, #0 + strh r0, [r3] + pop {lr} + + bx lr + +waitsync: + ldrh r0, [r3] + and r0, r0, #0x000f + cmp r0, r2 + bne waitsync + bx lr +waitcode_end: + +arm7base: + .word 0x037f8000 +arm7bootaddr: + .word 0x02FFFE34 +arm9bootaddr: + .word 0x02FFFE24 +tcmpudisable: + .word 0x2078 + +resetcode: + .word 0x0c04000c + +//----------------------------------------------------------------- +hook7from9: +//----------------------------------------------------------------- + mov r12, #0x04000000 + strb r12, [r12,#0x208] + + .arch armv5te + .cpu arm946e-s + + ldr r1, tcmpudisable @ disable TCM and protection unit + mcr p15, 0, r1, c1, c0 + + @ Disable cache + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Instruction cache + mcr p15, 0, r0, c7, c6, 0 @ Data cache + mcr p15, 0, r0, c3, c0, 0 @ write buffer + + @ Wait for write buffer to empty + mcr p15, 0, r0, c7, c10, 4 + + add r3, r12, #0x180 @ r3 = 4000180 + + mov r0,#0x80 + strb r0,[r3,#0x242-0x180] + + adr r0, _loader + ldr r2, _loader_size + mov r1, #0x06800000 + add r1, r1, #0x40000 + add r2, r0, r2 +_copyloader: + ldr r4, [r0], #4 + str r4, [r1], #4 + cmp r0, r2 + blt _copyloader + + mov r0,#0x82 + strb r0,[r3,#0x242-0x180] + + ldrh r0,[r3,#0x204-0x180] + orr r0,r0,#(1<<11) | (1<<7) + strh r0,[r3,#0x204-0x180] + + + ldr r0, arm7bootaddr + mov r1, #0x06000000 + str r1, [r0] + + ldr r0, resetcode + str r0, [r12, #0x188] + + mov r2, #1 + bl waitsync + + mov r0, #0x100 + strh r0, [r3] + + mov r2, #0 + bl waitsync + + mov r0, #0 + strh r0, [r3] + +// set up and enter passme loop + + ldr r0,arm9branchaddr + ldr r1,branchinst + str r1,[r0] + str r0,[r0,#0x20] + + bx r0 + +branchinst: + .word 0xE59FF018 + +arm9branchaddr: + .word 0x02fffe04 + + +_loader: diff --git a/clean and compile.bat b/clean and compile.bat new file mode 100644 index 0000000..3260f43 --- /dev/null +++ b/clean and compile.bat @@ -0,0 +1,3 @@ +make clean +make +pause diff --git a/compile.bat b/compile.bat new file mode 100644 index 0000000..9bd9005 --- /dev/null +++ b/compile.bat @@ -0,0 +1,2 @@ +make +pause