mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-06-18 10:55:31 -04:00
Add source code files
This commit is contained in:
parent
cc9dad4a2d
commit
81fc6b9754
1
GodMoDeS.pnproj
Normal file
1
GodMoDeS.pnproj
Normal file
File diff suppressed because one or more lines are too long
1
GodMoDeS.pnps
Normal file
1
GodMoDeS.pnps
Normal file
@ -0,0 +1 @@
|
|||||||
|
<pd><ViewState><e p="HomebrewMenu\arm7" x="false"></e><e p="HomebrewMenu\arm9\(raw) include" x="false"></e><e p="HomebrewMenu\arm9\source\common" x="false"></e><e p="HomebrewMenu\bootloader" x="false"></e><e p="HomebrewMenu" x="true"></e><e p="HomebrewMenu\arm9\build" x="false"></e><e p="HomebrewMenu\arm9\include" x="false"></e><e p="HomebrewMenu\arm9\source" x="true"></e><e p="HomebrewMenu\arm9\source\graphics" x="true"></e><e p="HomebrewMenu\BootStrap" x="false"></e><e p="HomebrewMenu\arm9" x="true"></e><e p="HomebrewMenu\bootstub" x="false"></e></ViewState></pd>
|
193
Makefile
Normal file
193
Makefile
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SECONDARY:
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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
|
||||||
|
#---------------------------------------------------------------------------------------
|
135
arm7/Makefile
Normal file
135
arm7/Makefile
Normal file
@ -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=<path to>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
|
||||||
|
#---------------------------------------------------------------------------------------
|
176
arm7/ds_arm7_ram.ld
Normal file
176
arm7/ds_arm7_ram.ld
Normal file
@ -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 . */
|
||||||
|
}
|
112
arm7/source/main.c
Normal file
112
arm7/source/main.c
Normal file
@ -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 <nds.h>
|
||||||
|
#include <maxmod7.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
154
arm9/Makefile
Normal file
154
arm9/Makefile
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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
|
||||||
|
#---------------------------------------------------------------------------------------
|
110
arm9/source/date.cpp
Normal file
110
arm9/source/date.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "date.h"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
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]);
|
||||||
|
}
|
47
arm9/source/date.h
Normal file
47
arm9/source/date.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef DATE_H
|
||||||
|
#define DATE_H
|
||||||
|
|
||||||
|
#include <nds.h>
|
||||||
|
#include <string>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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
|
69
arm9/source/fileOperations.cpp
Normal file
69
arm9/source/fileOperations.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
7
arm9/source/fileOperations.h
Normal file
7
arm9/source/fileOperations.h
Normal file
@ -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
|
245
arm9/source/file_browse.cpp
Normal file
245
arm9/source/file_browse.cpp
Normal file
@ -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 <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <nds.h>
|
||||||
|
|
||||||
|
#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<string> 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<DirEntry>& dirContents, const vector<string> 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<DirEntry>& dirContents) {
|
||||||
|
vector<string> extensionList;
|
||||||
|
getDirectoryContents (dirContents, extensionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showDirectoryContents (const vector<DirEntry>& 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<string> extensionList) {
|
||||||
|
int pressed = 0;
|
||||||
|
int screenOffset = 0;
|
||||||
|
int fileOffset = 0;
|
||||||
|
off_t fileSize = 0;
|
||||||
|
vector<DirEntry> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
arm9/source/file_browse.h
Normal file
32
arm9/source/file_browse.h
Normal file
@ -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 <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::string browseForFile (const std::vector<std::string> extensionList);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FILE_BROWSE_H
|
145
arm9/source/main.cpp
Normal file
145
arm9/source/main.cpp
Normal file
@ -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 <nds.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fat.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#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<string> 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<char*> 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;
|
||||||
|
}
|
436
arm9/source/nds_loader_arm9.c
Normal file
436
arm9/source/nds_loader_arm9.c
Normal file
@ -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 <string.h>
|
||||||
|
#include <nds.h>
|
||||||
|
#include <nds/arm9/dldi.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fat.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
42
arm9/source/nds_loader_arm9.h
Normal file
42
arm9/source/nds_loader_arm9.h
Normal file
@ -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
|
123
bootloader/Makefile
Normal file
123
bootloader/Makefile
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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
|
||||||
|
#---------------------------------------------------------------------------------------
|
110
bootloader/arm9code/mpu_reset.s
Normal file
110
bootloader/arm9code/mpu_reset.s
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nds/arm9/cache_asm.h>
|
||||||
|
|
||||||
|
.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
|
198
bootloader/load.ld
Normal file
198
bootloader/load.ld
Normal file
@ -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 . */
|
||||||
|
}
|
70
bootloader/source/arm7clear.s
Normal file
70
bootloader/source/arm7clear.s
Normal file
@ -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
|
||||||
|
|
112
bootloader/source/arm9clear.arm.c
Normal file
112
bootloader/source/arm9clear.arm.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#define ARM9
|
||||||
|
#undef ARM7
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <nds/dma.h>
|
||||||
|
#include <nds/system.h>
|
||||||
|
#include <nds/interrupts.h>
|
||||||
|
#include <nds/timers.h>
|
||||||
|
|
||||||
|
#include <nds/memory.h>
|
||||||
|
#include <nds/arm9/video.h>
|
||||||
|
#include <nds/arm9/input.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
6
bootloader/source/arm9mpu_reset.s
Normal file
6
bootloader/source/arm9mpu_reset.s
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.arm
|
||||||
|
.global mpu_reset, mpu_reset_end
|
||||||
|
|
||||||
|
mpu_reset:
|
||||||
|
.incbin "mpu_reset.bin"
|
||||||
|
mpu_reset_end:
|
13
bootloader/source/bios.s
Normal file
13
bootloader/source/bios.s
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.global swiDelay
|
||||||
|
.thumb_func
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swiDelay:
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swi 0x03
|
||||||
|
bx lr
|
314
bootloader/source/boot.c
Normal file
314
bootloader/source/boot.c
Normal file
@ -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 <nds/ndstypes.h>
|
||||||
|
#include <nds/dma.h>
|
||||||
|
#include <nds/system.h>
|
||||||
|
#include <nds/interrupts.h>
|
||||||
|
#include <nds/timers.h>
|
||||||
|
#define ARM9
|
||||||
|
#undef ARM7
|
||||||
|
#include <nds/memory.h>
|
||||||
|
#include <nds/arm9/video.h>
|
||||||
|
#include <nds/arm9/input.h>
|
||||||
|
#undef ARM9
|
||||||
|
#define ARM7
|
||||||
|
#include <nds/arm7/audio.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
12
bootloader/source/boot.h
Normal file
12
bootloader/source/boot.h
Normal file
@ -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_
|
45
bootloader/source/card.h
Normal file
45
bootloader/source/card.h
Normal file
@ -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
|
82
bootloader/source/disc_io.h
Normal file
82
bootloader/source/disc_io.h
Normal file
@ -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 <nds/ndstypes.h>
|
||||||
|
#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
|
208
bootloader/source/dldi_patcher.c
Normal file
208
bootloader/source/dldi_patcher.c
Normal file
@ -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 <string.h>
|
||||||
|
#include <nds.h>
|
||||||
|
#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
|
32
bootloader/source/dldi_patcher.h
Normal file
32
bootloader/source/dldi_patcher.h
Normal file
@ -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 <nds/ndstypes.h>
|
||||||
|
|
||||||
|
typedef signed int addr_t;
|
||||||
|
typedef unsigned char data_t;
|
||||||
|
bool dldiPatchBinary (data_t *binData, u32 binSize);
|
||||||
|
|
||||||
|
#endif // DLDI_PATCHER_H
|
585
bootloader/source/fat.c
Normal file
585
bootloader/source/fat.c
Normal file
@ -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;
|
||||||
|
}
|
46
bootloader/source/fat.h
Normal file
46
bootloader/source/fat.h
Normal file
@ -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 <nds/ndstypes.h>
|
||||||
|
|
||||||
|
#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
|
44
bootloader/source/io_dldi.h
Normal file
44
bootloader/source/io_dldi.h
Normal file
@ -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
|
124
bootloader/source/io_dldi.s
Normal file
124
bootloader/source/io_dldi.s
Normal file
@ -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
|
144
bootloader/source/load_crt0.s
Normal file
144
bootloader/source/load_crt0.s
Normal file
@ -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
|
||||||
|
@---------------------------------------------------------------------------------
|
301
bootloader/source/sdmmc.c
Normal file
301
bootloader/source/sdmmc.c
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
#ifndef NO_SDMMC
|
||||||
|
#include <nds/bios.h>
|
||||||
|
#include <nds/arm7/sdmmc.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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
|
13
bootstub/Makefile
Normal file
13
bootstub/Makefile
Normal file
@ -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
|
176
bootstub/bootstub.s
Normal file
176
bootstub/bootstub.s
Normal file
@ -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:
|
3
clean and compile.bat
Normal file
3
clean and compile.bat
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
make clean
|
||||||
|
make
|
||||||
|
pause
|
2
compile.bat
Normal file
2
compile.bat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
make
|
||||||
|
pause
|
Loading…
Reference in New Issue
Block a user