mirror of
https://github.com/ApacheThunder/ysMenuBootstrap.git
synced 2025-06-19 11:45:38 -04:00
Initial Commit....
This commit is contained in:
parent
28003c9ce9
commit
358f0666e8
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
*.DAT
|
||||||
|
*.dat
|
||||||
|
*.NDS
|
||||||
|
*.nds
|
||||||
|
*.elf
|
||||||
|
*.bz2
|
||||||
|
*.dsi
|
||||||
|
*.cia
|
||||||
|
*.zip
|
||||||
|
BootStrap/arm7/build
|
||||||
|
BootStrap/arm9/build
|
||||||
|
data
|
||||||
|
build
|
||||||
|
hbmenu
|
8
.gitmodules
vendored
Normal file
8
.gitmodules
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[submodule "bootloader"]
|
||||||
|
path = bootloader
|
||||||
|
url = git@github.com:devkitPro/nds-bootloader.git
|
||||||
|
branch = master
|
||||||
|
[submodule "nds-exception-stub"]
|
||||||
|
path = nds-exception-stub
|
||||||
|
url = git@github.com:devkitPro/nds-exception-stub.git
|
||||||
|
branch = master
|
BIN
BootStrap/EZ5V2.dldi
Normal file
BIN
BootStrap/EZ5V2.dldi
Normal file
Binary file not shown.
110
BootStrap/Makefile
Normal file
110
BootStrap/Makefile
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
export TARGET := bootstrap
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: checkarm7 checkarm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: checkarm7 checkarm9 \
|
||||||
|
_ds_menu.dat ismat.dat ez5sys.bin \
|
||||||
|
akmenu4.nds TTMENU.DAT _BOOT_MP.NDS \
|
||||||
|
ACE3DS/_ds_menu.dat ACE3DS/_dsmenu.dat
|
||||||
|
# AUTORUN1.NDS
|
||||||
|
|
||||||
|
_ds_menu.dat : $(TARGET).nds r4tfv2.dldi
|
||||||
|
@cp $(TARGET).nds _ds_menu.nds
|
||||||
|
@dlditool r4tfv2.dldi _ds_menu.nds
|
||||||
|
@r4denc $< _ds_menu.nds $@
|
||||||
|
|
||||||
|
ACE3DS/_ds_menu.dat : $(TARGET).nds ace3ds_sd.dldi
|
||||||
|
@[ -d ACE3DS ] || mkdir -p ACE3DS
|
||||||
|
@cp $(TARGET).nds ACE3DS/_ds_menu.nds
|
||||||
|
@dlditool ace3ds_sd.dldi ACE3DS/_ds_menu.nds
|
||||||
|
@r4denc --key 0x4002 ACE3DS/_ds_menu.nds $@
|
||||||
|
|
||||||
|
# Alternative name for some ACE3DS clones.
|
||||||
|
ACE3DS/_dsmenu.dat : $(TARGET).nds ace3ds_sd.dldi
|
||||||
|
@[ -d ACE3DS ] || mkdir -p ACE3DS
|
||||||
|
@cp $(TARGET).nds ACE3DS/_dsmenu.nds
|
||||||
|
@dlditool ace3ds_sd.dldi ACE3DS/_dsmenu.nds
|
||||||
|
@r4denc --key 0x4002 ACE3DS/_dsmenu.nds $@
|
||||||
|
|
||||||
|
ez5sys.bin : $(TARGET).nds EZ5V2.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool EZ5V2.dldi $@
|
||||||
|
|
||||||
|
akmenu4.nds : $(TARGET).nds ak2_sd.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool ak2_sd.dldi $@
|
||||||
|
|
||||||
|
TTMENU.DAT : $(TARGET).nds TTCARDIOLibrary.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool TTCARDIOLibrary.dldi $@
|
||||||
|
|
||||||
|
_BOOT_MP.NDS : $(TARGET).nds mpcf.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool mpcf.dldi $@
|
||||||
|
|
||||||
|
ismat.dat : $(TARGET).nds mati.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool mati.dldi $@
|
||||||
|
|
||||||
|
AUTORUN1.NDS : $(TARGET).nds nrio.dldi
|
||||||
|
@cp $< $@
|
||||||
|
@dlditool nrio.dldi $@
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Building separate .dsi and .nds binaries here is done purely to allow the .nds
|
||||||
|
# binary to be used to replace various flashcart boot menus.
|
||||||
|
#
|
||||||
|
# This is *NOT* for general use, standard .nds files with a full header are DSi
|
||||||
|
# hybrid binaries.
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
bootstrap.cia: bootstrap.dsi
|
||||||
|
make_cia --srl=bootstrap.dsi
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
bootstrap.dsi : $(TARGET).arm7.elf $(TARGET).arm9i.elf
|
||||||
|
ndstool -u 00030004 -g HBLA -b bootstrap.bmp "nds-hb-menu bootstrap;built with devkitARM;http://devkitpro.org" -c $@ -7 $(TARGET).arm7.elf -9 $(TARGET).arm9i.elf
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).nds : $(TARGET).arm7.elf $(TARGET).arm9.elf
|
||||||
|
ndstool -g "####" "##" "R4XX" -h 0x200 -c $(TARGET).nds -7 $(TARGET).arm7.elf -9 $(TARGET).arm9.elf
|
||||||
|
|
||||||
|
checkarm7:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
checkarm9:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).arm7.elf:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).arm9.elf:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).arm9i.elf:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C arm9 clean
|
||||||
|
$(MAKE) -C arm7 clean
|
||||||
|
rm -f $(TARGET).nds $(TARGET).arm7.elf $(TARGET).arm9.elf _ds_menu.dat ez5sys.bin akmenu4.nds TTMENU.DAT _BOOT_MP.NDS ismat.dat
|
||||||
|
rm -fr ACE3DS
|
||||||
|
rm -f bootstrap.dsi $(TARGET).arm9i.elf bootstrap.cia
|
||||||
|
|
9
BootStrap/README.TXT
Normal file
9
BootStrap/README.TXT
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
This subfolder builds bootstrap code for some popular DS flash cards and should be reasonably easy to modify for others. Essentially it's just a matter of patching the bootstrap code with the appropriate dldi.
|
||||||
|
|
||||||
|
The main issues users will have here is where the card menu is encrypted in some way or if the supplied dldi has been built with arm9 code. Hbmenu uses the arm7 to load code in order to allow the maximum use of memory.
|
||||||
|
|
||||||
|
The encoder/decoder for the R4 menu is available in devkitPro svn.
|
||||||
|
|
||||||
|
svn co https://devkitpro.svn.sourceforge.net/svnroot/devkitpro/trunk/projects/tools/r4denc r4denc
|
||||||
|
|
||||||
|
compile this and place it somewhere in your path.
|
BIN
BootStrap/TTCARDIOLibrary.dldi
Normal file
BIN
BootStrap/TTCARDIOLibrary.dldi
Normal file
Binary file not shown.
BIN
BootStrap/ace3ds_sd.dldi
Normal file
BIN
BootStrap/ace3ds_sd.dldi
Normal file
Binary file not shown.
BIN
BootStrap/ak2_sd.dldi
Normal file
BIN
BootStrap/ak2_sd.dldi
Normal file
Binary file not shown.
126
BootStrap/arm7/Makefile
Normal file
126
BootStrap/arm7/Makefile
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
INCLUDES := include build
|
||||||
|
DATA :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -mthumb-interwork
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2\
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||||
|
-ffast-math \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -DARM7
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=ds_arm7.specs -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 ARM7ELF := $(TOPDIR)/$(TARGET).arm7.elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
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)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(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 CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$(ARM7ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
63
BootStrap/arm7/source/template.c
Normal file
63
BootStrap/arm7/source/template.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void VcountHandler() {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
inputGetAndSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int main() {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
irqInit();
|
||||||
|
|
||||||
|
// read User Settings from firmware
|
||||||
|
readUserSettings();
|
||||||
|
|
||||||
|
// Start the RTC tracking IRQ
|
||||||
|
initClockIRQ();
|
||||||
|
|
||||||
|
fifoInit();
|
||||||
|
|
||||||
|
SetYtrigger(80);
|
||||||
|
|
||||||
|
installSystemFIFO();
|
||||||
|
|
||||||
|
irqSet(IRQ_VCOUNT, VcountHandler);
|
||||||
|
|
||||||
|
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
|
||||||
|
|
||||||
|
// Keep the ARM7 mostly idle
|
||||||
|
while (1) swiWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
138
BootStrap/arm9/Makefile
Normal file
138
BootStrap/arm9/Makefile
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source ../../source
|
||||||
|
INCLUDES := include ../../source
|
||||||
|
DATA := ../../data
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 -D_NO_BOOTSTUB_
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
|
||||||
|
|
||||||
|
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(TARGET).map
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -lfat -lnds9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export ARM9ELF := $(TOPDIR)/$(TARGET).arm9.elf
|
||||||
|
export ARM9iELF := $(TOPDIR)/$(TARGET).arm9i.elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := bootstrap.c nds_loader_arm9.c
|
||||||
|
CPPFILES :=
|
||||||
|
PNGFILES :=
|
||||||
|
SFILES :=
|
||||||
|
BINFILES := load.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),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) bootloader clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf *.nds* *.bin
|
||||||
|
|
||||||
|
../../data:
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
bootloader: ../../data
|
||||||
|
@$(MAKE) -C ../../bootloader
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(ARM9ELF) $(ARM9iELF)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM9ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) -Wl,--defsym,__secure_area__=0 -Wl,--section-start,.crt0=0x02000450,--nmagic -Wl,-Map,arm9.map $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
$(ARM9iELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -Wl,-Map,arm9i.map -o $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
37
BootStrap/arm9/source/bootstrap.c
Normal file
37
BootStrap/arm9/source/bootstrap.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <nds.h>
|
||||||
|
#include <fat.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "nds_loader_arm9.h"
|
||||||
|
|
||||||
|
int main( int argc, char **argv) {
|
||||||
|
consoleDemoInit();
|
||||||
|
iprintf("hbmenu bootstrap ...\n");
|
||||||
|
if (fatInitDefault()) {
|
||||||
|
runNdsFile("/BOOT.NDS", 0, NULL);
|
||||||
|
} else {
|
||||||
|
iprintf("FAT init failed!\n");
|
||||||
|
}
|
||||||
|
while(1) swiWaitForVBlank();
|
||||||
|
}
|
354
BootStrap/arm9/source/nds_loader_arm9.c
Normal file
354
BootStrap/arm9/source/nds_loader_arm9.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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"
|
||||||
|
#include "exceptionstub_bin.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "nds_loader_arm9.h"
|
||||||
|
|
||||||
|
#define TMP_DATA 0x02100000
|
||||||
|
|
||||||
|
#define LCDC_BANK_D (u16*)0x06860000
|
||||||
|
#define STORED_FILE_CLUSTER (*(((u32*)LCDC_BANK_D) + 1))
|
||||||
|
#define INIT_DISC (*(((u32*)LCDC_BANK_D) + 2))
|
||||||
|
#define WANT_TO_PATCH_DLDI (*(((u32*)LCDC_BANK_D) + 3))
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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)return false; // does not have a DLDI section
|
||||||
|
|
||||||
|
pDH = (data_t*)(io_dldi_data);
|
||||||
|
|
||||||
|
pAH = &(binData[patchOffset]);
|
||||||
|
|
||||||
|
if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI)return false; // No DLDI patch
|
||||||
|
|
||||||
|
if (pDH[DO_driverSize] > pAH[DO_allocatedSpace])return false; // Not enough space for patch
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
eRunNdsRetCode 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_D_CR = VRAM_ENABLE | VRAM_D_LCD;
|
||||||
|
// Load the loader/patcher into the correct address
|
||||||
|
vramcpy (LCDC_BANK_D, loader, loaderSize);
|
||||||
|
|
||||||
|
// Set the parameters for the loader
|
||||||
|
// STORED_FILE_CLUSTER = cluster;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, STORED_FILE_CLUSTER_OFFSET, cluster);
|
||||||
|
// INIT_DISC = initDisc;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, INIT_DISC_OFFSET, initDisc);
|
||||||
|
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, DSIMODE_OFFSET, isDSiMode());
|
||||||
|
if(argv[0][0]=='s' && argv[0][1]=='d') {
|
||||||
|
dldiPatchNds = false;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, HAVE_DSISD_OFFSET, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WANT_TO_PATCH_DLDI = dldiPatchNds;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, WANT_TO_PATCH_DLDI_OFFSET, dldiPatchNds);
|
||||||
|
// Give arguments to loader
|
||||||
|
argStart = (char*)LCDC_BANK_D + readAddr((data_t*)LCDC_BANK_D, 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_D, ARG_START_OFFSET, (addr_t)argStart - (addr_t)LCDC_BANK_D);
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, ARG_SIZE_OFFSET, argSize);
|
||||||
|
|
||||||
|
if(dldiPatchNds) {
|
||||||
|
// Patch the loader with a DLDI for the card
|
||||||
|
if (!dldiPatchLoader ((data_t*)LCDC_BANK_D, loaderSize, initDisc))return RUN_NDS_PATCH_DLDI_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqDisable(IRQ_ALL);
|
||||||
|
|
||||||
|
// Give the VRAM to the ARM7
|
||||||
|
VRAM_D_CR = VRAM_ENABLE | VRAM_D_ARM7_0x06020000;
|
||||||
|
// 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(0x06020000);
|
||||||
|
|
||||||
|
swiSoftReset();
|
||||||
|
return RUN_NDS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
eRunNdsRetCode 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 RUN_NDS_STAT_FAILED;
|
||||||
|
|
||||||
|
if (argc <= 0 || !argv) {
|
||||||
|
// Construct a command line if we weren't supplied with one
|
||||||
|
if (!getcwd (filePath, PATH_MAX))return RUN_NDS_GETCWD_FAILED;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void(*exceptionstub)(void) = (void(*)(void))0x2FFA000;
|
||||||
|
|
||||||
|
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;
|
||||||
|
memcpy(exceptionstub,exceptionstub_bin,exceptionstub_bin_size);
|
||||||
|
exceptionstub();
|
||||||
|
DC_FlushAll();
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
50
BootStrap/arm9/source/nds_loader_arm9.h
Normal file
50
BootStrap/arm9/source/nds_loader_arm9.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RUN_NDS_OK = 0,
|
||||||
|
RUN_NDS_STAT_FAILED,
|
||||||
|
RUN_NDS_GETCWD_FAILED,
|
||||||
|
RUN_NDS_PATCH_DLDI_FAILED,
|
||||||
|
} eRunNdsRetCode;
|
||||||
|
|
||||||
|
#define LOAD_DEFAULT_NDS 0
|
||||||
|
|
||||||
|
eRunNdsRetCode runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool dldiPatchNds, int argc, const char** argv);
|
||||||
|
|
||||||
|
eRunNdsRetCode runNdsFile (const char* filename, int argc, const char** argv);
|
||||||
|
|
||||||
|
bool installBootStub(bool havedsiSD);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NDS_LOADER_ARM7_H
|
||||||
|
|
BIN
BootStrap/bootstrap.bmp
Normal file
BIN
BootStrap/bootstrap.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 630 B |
BIN
BootStrap/mati.dldi
Normal file
BIN
BootStrap/mati.dldi
Normal file
Binary file not shown.
BIN
BootStrap/mpcf.dldi
Normal file
BIN
BootStrap/mpcf.dldi
Normal file
Binary file not shown.
BIN
BootStrap/nrio.dldi
Normal file
BIN
BootStrap/nrio.dldi
Normal file
Binary file not shown.
BIN
BootStrap/r4tfv2.dldi
Normal file
BIN
BootStrap/r4tfv2.dldi
Normal file
Binary file not shown.
342
COPYING
Normal file
342
COPYING
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
112
Makefile
Normal file
112
Makefile
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
export TARGET := _DS_MENU
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export HBMENU_MAJOR := 0
|
||||||
|
export HBMENU_MINOR := 9
|
||||||
|
export HBMENU_PATCH := 3
|
||||||
|
|
||||||
|
|
||||||
|
VERSION := $(HBMENU_MAJOR).$(HBMENU_MINOR).$(HBMENU_PATCH)
|
||||||
|
|
||||||
|
# GMAE_ICON is the image used to create the game icon, leave blank to use default rule
|
||||||
|
GAME_ICON :=
|
||||||
|
|
||||||
|
# specify a directory which contains the nitro filesystem
|
||||||
|
# this is relative to the Makefile
|
||||||
|
NITRO_FILES :=
|
||||||
|
|
||||||
|
# These set the information text in the nds file
|
||||||
|
#GAME_TITLE := My Wonderful Homebrew
|
||||||
|
#GAME_SUBTITLE1 := built with devkitARM
|
||||||
|
#GAME_SUBTITLE2 := http://devitpro.org
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
# .PHONY: data ndsbootloader bootstub BootStrap exceptionstub clean
|
||||||
|
.PHONY: data ndsbootloader bootstub BootStrap clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# all: ndsbootloader bootstub exceptionstub $(TARGET).nds BootStrap
|
||||||
|
all: ndsbootloader bootstub $(TARGET).nds BootStrap
|
||||||
|
|
||||||
|
cia:
|
||||||
|
$(MAKE) -C BootStrap bootstrap.cia
|
||||||
|
|
||||||
|
dist: all
|
||||||
|
rm -fr hbmenu
|
||||||
|
mkdir -p hbmenu/nds
|
||||||
|
ndstool -c boot.nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||||
|
-b $(CURDIR)/icon.bmp "hbmenu;$(VERSION);http://devkitpro.org"
|
||||||
|
cp boot.nds hbmenu/BOOT.NDS
|
||||||
|
cp BootStrap/_BOOT_MP.NDS BootStrap/TTMENU.DAT BootStrap/_ds_menu.dat BootStrap/ez5sys.bin BootStrap/akmenu4.nds BootStrap/ismat.dat hbmenu
|
||||||
|
cp -r BootStrap/ACE3DS hbmenu
|
||||||
|
ifneq (,$(wildcard BootStrap/bootstrap.cia))
|
||||||
|
cp "BootStrap/bootstrap.cia" hbmenu
|
||||||
|
endif
|
||||||
|
cp testfiles/* hbmenu/nds
|
||||||
|
zip -9r hbmenu-$(VERSION).zip hbmenu README.md COPYING
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
checkarm7:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
checkarm9:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||||
|
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||||
|
-b $(CURDIR)/icon.bmp "hbmenu;$(VERSION);http://devkitpro.org" \
|
||||||
|
-h 0x200
|
||||||
|
dlditool r4tfv3.dldi $(TARGET).nds
|
||||||
|
r4denc $(TARGET).nds _DS_MENU.DAT
|
||||||
|
|
||||||
|
# @cp $(TARGET).nds 00000000.app
|
||||||
|
|
||||||
|
data:
|
||||||
|
@mkdir -p data
|
||||||
|
|
||||||
|
ndsbootloader: data
|
||||||
|
$(MAKE) -C ndsbootloader LOADBIN=$(CURDIR)/data/load.bin
|
||||||
|
|
||||||
|
# exceptionstub: data
|
||||||
|
# $(MAKE) -C exception-stub STUBBIN=$(CURDIR)/data/exceptionstub.bin
|
||||||
|
|
||||||
|
bootstub: data
|
||||||
|
$(MAKE) -C bootstub
|
||||||
|
|
||||||
|
BootStrap: data
|
||||||
|
$(MAKE) -C BootStrap
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm7/$(TARGET).elf:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm9/$(TARGET).elf: ndsbootloader
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C arm9 clean
|
||||||
|
$(MAKE) -C arm7 clean
|
||||||
|
$(MAKE) -C ndsbootloader clean
|
||||||
|
$(MAKE) -C bootstub clean
|
||||||
|
$(MAKE) -C BootStrap clean
|
||||||
|
# $(MAKE) -C exception-stub clean
|
||||||
|
rm -rf data
|
||||||
|
rm -rf hbmenu
|
||||||
|
rm -f $(TARGET).nds
|
||||||
|
rm -f boot.nds
|
||||||
|
rm -f 00000000.app
|
||||||
|
rm -f _DS_MENU.DAT
|
||||||
|
|
42
Readme.md
42
Readme.md
@ -1 +1,43 @@
|
|||||||
|
# R4 Auto Boot Bootstrap
|
||||||
|
|
||||||
|
This is a modified build of HBMenu with UI enhancements but setup to act as a kernel/firmware replacement to original R4.
|
||||||
|
(though can use this with other carts if you provide your own DLDI file).
|
||||||
|
|
||||||
|
* Holding no button on boot cause it to auto boot R4TF.nds if present or Boot.nds if present.
|
||||||
|
* Holding A button will cause quick boot into GBA Mode. If a gbaframe.bmp file is present it will be loaded to. Curently setup to use gbaframe bmps made to work with GBA-Exploader.
|
||||||
|
* Holding B button will skip auto boot and bring up file browser so you can select a NDS file of your choice.
|
||||||
|
|
||||||
|
Currently the gbaframe loader is setup to load GBA-Exploader compatible BMP files. The directories it will check are as follows in the indicated order:
|
||||||
|
|
||||||
|
1. fat:/gbaframe.bmp
|
||||||
|
2. fat:/GBA_SIGN/gbaframe.bmp
|
||||||
|
3. fat:/_system_/gbaframe.bmp
|
||||||
|
4. fat:/ttmenu/gbaframe.bmp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
Note: While the GPL license allows you to distribute modified versions of this program it would be appreciated if any improvements are contributed to devkitPro. Ultimately the community as a whole is better served by having a single official source for tools, applications and libraries.
|
||||||
|
|
||||||
|
The latest sources may be obtained from devkitPro git using the command: `git clone git@github.com:devkitPro/nds-hb-menu.git`
|
||||||
|
|
||||||
|
```
|
||||||
|
Copyright (C) 2005 - 2017
|
||||||
|
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.
|
||||||
|
```
|
||||||
|
124
arm7/Makefile
Normal file
124
arm7/Makefile
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
INCLUDES := include build
|
||||||
|
DATA :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -mthumb-interwork
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2 \
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||||
|
-ffast-math \
|
||||||
|
$(ARCH) $(INCLUDE) -DARM7
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).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 ARM7ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(DATA),$(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)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
|
||||||
|
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
|
||||||
|
|
||||||
|
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include)\
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM7ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
15
arm7/source/biosCalls.s
Normal file
15
arm7/source/biosCalls.s
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.TEXT
|
||||||
|
.ARM
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------------
|
||||||
|
.GLOBAL swiSwitchToGBAModeFixed
|
||||||
|
.func swiSwitchToGBAModeFixed
|
||||||
|
@---------------------------------------------------------------------------------------
|
||||||
|
swiSwitchToGBAModeFixed:
|
||||||
|
mov r2,#0x40
|
||||||
|
swi 0x1f0000
|
||||||
|
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
.end
|
||||||
|
|
67
arm7/source/main.c
Normal file
67
arm7/source/main.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
|
||||||
|
volatile bool switchedMode = false;
|
||||||
|
volatile bool exitflag = false;
|
||||||
|
|
||||||
|
// libnds messed up the original SWI bios call ASM.
|
||||||
|
// They used r0 instead of r2. This reimplementation fixes that issue for now.
|
||||||
|
extern void swiSwitchToGBAModeFixed();
|
||||||
|
|
||||||
|
void powerButtonCB() { exitflag = true; }
|
||||||
|
|
||||||
|
void gbaMode() {
|
||||||
|
vu32 vr;
|
||||||
|
|
||||||
|
REG_IME = IME_DISABLE;
|
||||||
|
for(vr = 0; vr < 0x1000; vr++); // Wait ARM9
|
||||||
|
|
||||||
|
if (PersonalData->gbaScreen) {
|
||||||
|
writePowerManagement(PM_CONTROL_REG, PM_BACKLIGHT_BOTTOM | PM_SOUND_AMP);
|
||||||
|
} else {
|
||||||
|
writePowerManagement(PM_CONTROL_REG, PM_BACKLIGHT_TOP | PM_SOUND_AMP);
|
||||||
|
}
|
||||||
|
swiSwitchToGBAModeFixed();
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fifoCheckHandler() {
|
||||||
|
if (!switchedMode) {
|
||||||
|
if (fifoCheckValue32(FIFO_USER_01)) {
|
||||||
|
switchedMode = true;
|
||||||
|
gbaMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VblankHandler() { fifoCheckHandler(); }
|
||||||
|
void VcountHandler() { inputGetAndSend(); }
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
readUserSettings();
|
||||||
|
ledBlink(0);
|
||||||
|
|
||||||
|
irqInit();
|
||||||
|
|
||||||
|
initClockIRQ();
|
||||||
|
fifoInit();
|
||||||
|
touchInit();
|
||||||
|
|
||||||
|
SetYtrigger(80);
|
||||||
|
|
||||||
|
installSystemFIFO();
|
||||||
|
|
||||||
|
irqSet(IRQ_VCOUNT, VcountHandler);
|
||||||
|
irqSet(IRQ_VBLANK, VblankHandler);
|
||||||
|
|
||||||
|
irqEnable(IRQ_VBLANK | IRQ_VCOUNT);
|
||||||
|
|
||||||
|
setPowerButtonCB(powerButtonCB);
|
||||||
|
|
||||||
|
if (REG_SNDEXTCNT != 0) {
|
||||||
|
i2cWriteRegister(0x4A, 0x12, 0x00); // Press power-button for auto-reset
|
||||||
|
i2cWriteRegister(0x4A, 0x70, 0x01); // Bootflag = Warmboot/SkipHealthSafety
|
||||||
|
}
|
||||||
|
while(1)swiWaitForVBlank();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
143
arm9/Makefile
Normal file
143
arm9/Makefile
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
# DATA is a list of directories containing binary files embedded using bin2o
|
||||||
|
# GRAPHICS is a list of directories containing image files to be converted with grit
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
INCLUDES := include
|
||||||
|
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 -D_NO_BOOTSTUB_
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=dsi_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -lfat -lnds329
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS) $(PORTLIBS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export ARM9ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
|
||||||
|
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export OFILES := $(PNGFILES:.png=.o) $(OFILES_BIN) $(OFILES_SOURCES)
|
||||||
|
|
||||||
|
export HFILES := $(PNGFILES:.png=.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include)\
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM9ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# This rule creates assembly source files using grit
|
||||||
|
# grit takes an image file and a .grit describing how the file is to be processed
|
||||||
|
# add additional rules like this for each image extension
|
||||||
|
# you use in the graphics folders
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.s %.h: %.png %.grit
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
grit $< -fts -o$*
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
|
25
arm9/gfx/font.grit
Normal file
25
arm9/gfx/font.grit
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#-------------------------------------------------------
|
||||||
|
# graphics in tile format
|
||||||
|
#-------------------------------------------------------
|
||||||
|
-gt
|
||||||
|
|
||||||
|
#-------------------------------------------------------
|
||||||
|
# output first 16 colors of the palette
|
||||||
|
#-------------------------------------------------------
|
||||||
|
-pw16
|
||||||
|
|
||||||
|
#-------------------------------------------------------
|
||||||
|
# no tile reduction
|
||||||
|
#-------------------------------------------------------
|
||||||
|
-mR!
|
||||||
|
|
||||||
|
#-------------------------------------------------------
|
||||||
|
# no map output
|
||||||
|
#-------------------------------------------------------
|
||||||
|
-m!
|
||||||
|
|
||||||
|
#-------------------------------------------------------
|
||||||
|
# graphics bit depth is 4 (16 color)
|
||||||
|
#-------------------------------------------------------
|
||||||
|
-gB4
|
||||||
|
|
BIN
arm9/gfx/font.png
Normal file
BIN
arm9/gfx/font.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 688 B |
4
arm9/gfx/font6x8.grit
Normal file
4
arm9/gfx/font6x8.grit
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
-gB8
|
||||||
|
-gTFFFFFF
|
||||||
|
# use lz77 compression
|
||||||
|
-gzl
|
BIN
arm9/gfx/font6x8.png
Normal file
BIN
arm9/gfx/font6x8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 758 B |
9
arm9/gfx/hbmenu_banner.grit
Normal file
9
arm9/gfx/hbmenu_banner.grit
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-W3
|
||||||
|
# disable alpha and set opaque bit for all pixels
|
||||||
|
-gT!
|
||||||
|
|
||||||
|
# use lz77 compression
|
||||||
|
-gzl
|
||||||
|
|
||||||
|
# 16 bit bitmap
|
||||||
|
-gB16
|
BIN
arm9/gfx/hbmenu_banner.png
Normal file
BIN
arm9/gfx/hbmenu_banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
5
arm9/gfx/hbmenu_consolebg.grit
Normal file
5
arm9/gfx/hbmenu_consolebg.grit
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# 8 bit bitmap
|
||||||
|
-gB8
|
||||||
|
|
||||||
|
# bitmap format
|
||||||
|
-gb
|
BIN
arm9/gfx/hbmenu_consolebg.png
Normal file
BIN
arm9/gfx/hbmenu_consolebg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
arm9/include/hbNoIcon.bin
Normal file
BIN
arm9/include/hbNoIcon.bin
Normal file
Binary file not shown.
294
arm9/source/args.cpp
Normal file
294
arm9/source/args.cpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
Copyright (C) 2005 - 2017
|
||||||
|
Michael "Chishm" Chisholm
|
||||||
|
Dave "WinterMute" Murphy
|
||||||
|
Claudio "sverx"
|
||||||
|
Michael "mtheall" Theall
|
||||||
|
|
||||||
|
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 <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "args.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static const string NDS_EXT = ".nds";
|
||||||
|
static const string ARG_EXT = ".argv";
|
||||||
|
static const string EXT_EXT = ".ext";
|
||||||
|
static const char EXT_DIR[] = "/nds";
|
||||||
|
static const char SEPARATORS[] = "\n\r\t ";
|
||||||
|
|
||||||
|
/* Checks if s1 ends with s2, ignoring case.
|
||||||
|
Returns true if it does, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool strCaseEnd(const string& s1, const string& s2) {
|
||||||
|
return (s1.size() >= s2.size() &&
|
||||||
|
strcasecmp(s1.c_str() + s1.size() - s2.size(), s2.c_str()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parses the contents of the file given by filename into argarray. Arguments
|
||||||
|
are tokenized based on whitespace.
|
||||||
|
*/
|
||||||
|
static bool parseArgFileAll(const string& filename, vector<string>& argarray) {
|
||||||
|
FILE *argfile = fopen(filename.c_str(), "rb");
|
||||||
|
if (!argfile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
size_t lineSize = 0;
|
||||||
|
while (__getline(&line, &lineSize, argfile) >= 0) {
|
||||||
|
// Find comment and end string there
|
||||||
|
char *pstr = strchr(line, '#');
|
||||||
|
if (pstr) {
|
||||||
|
*pstr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokenize arguments
|
||||||
|
char *saveptr;
|
||||||
|
pstr = strtok_r(line, SEPARATORS, &saveptr);
|
||||||
|
|
||||||
|
while (pstr) {
|
||||||
|
argarray.emplace_back(pstr);
|
||||||
|
pstr = strtok_r(NULL, SEPARATORS, &saveptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line) {
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(argfile);
|
||||||
|
|
||||||
|
return argarray.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parses the argument file given by filename and returns the NDS file that it
|
||||||
|
* points to.
|
||||||
|
*/
|
||||||
|
static bool parseArgFileNds(const std::string& filename, std::string& ndsPath) {
|
||||||
|
bool success = false;
|
||||||
|
FILE *argfile = fopen(filename.c_str(), "rb");
|
||||||
|
if (!argfile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
size_t lineSize = 0;
|
||||||
|
while (__getline(&line, &lineSize, argfile) >= 0) {
|
||||||
|
char *pstr = NULL;
|
||||||
|
|
||||||
|
// Find comment and end string there
|
||||||
|
pstr = strchr(line, '#');
|
||||||
|
if (pstr) {
|
||||||
|
*pstr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokenize arguments
|
||||||
|
char *saveptr;
|
||||||
|
pstr = strtok_r(line, SEPARATORS, &saveptr);
|
||||||
|
|
||||||
|
if (pstr) {
|
||||||
|
// Only want the first token, which should be the NDS file name
|
||||||
|
ndsPath = pstr;
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line) {
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(argfile);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a plain filename into an absolute path. If it's already an absolute
|
||||||
|
* path, it is returned as-is. If basePath is NULL, the current working directory
|
||||||
|
* is used.
|
||||||
|
* Returns true on success, false on failure.
|
||||||
|
*/
|
||||||
|
static bool toAbsPath(const string& filename, const char* basePath, string& filePath) {
|
||||||
|
// Copy existing absolute or empty paths
|
||||||
|
if (filename.size() == 0 || filename[0] == '/') {
|
||||||
|
filePath = filename;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basePath == NULL) {
|
||||||
|
// Get current working directory (uses C-strings)
|
||||||
|
vector<char> cwd(PATH_MAX);
|
||||||
|
if (getcwd (cwd.data(), cwd.size()) == NULL) {
|
||||||
|
// Path was too long, abort
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Copy CWD into path
|
||||||
|
filePath = cwd.data();
|
||||||
|
} else {
|
||||||
|
// Just copy the base path
|
||||||
|
filePath = basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure there's a path separator
|
||||||
|
if (filePath.back() != '/') {
|
||||||
|
filePath += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now append the filename
|
||||||
|
filePath += filename;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a dataFilePath to the path of the ext file that specifies the
|
||||||
|
* handler.
|
||||||
|
* Returns true on success, false on failure
|
||||||
|
*/
|
||||||
|
static bool toExtPath(const string& dataFilePath, string& extFilePath) {
|
||||||
|
// Figure out what the file extension is
|
||||||
|
size_t extPos = dataFilePath.rfind('.');
|
||||||
|
if (extPos == string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extPos += 1;
|
||||||
|
if (extPos >= dataFilePath.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct handler path from extension. Handlers are in the EXT_DIR and
|
||||||
|
// end with EXT_EXT.
|
||||||
|
const string ext = dataFilePath.substr(extPos);
|
||||||
|
if (!toAbsPath(ext, EXT_DIR, extFilePath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extFilePath += EXT_EXT;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool argsNdsPath(const std::string& filePath, std::string& ndsPath) {
|
||||||
|
if (strCaseEnd(filePath, NDS_EXT)) {
|
||||||
|
ndsPath = filePath;
|
||||||
|
return true;
|
||||||
|
} else if (strCaseEnd(filePath, ARG_EXT)) {
|
||||||
|
return parseArgFileNds(filePath, ndsPath);
|
||||||
|
} else {
|
||||||
|
// This is a data file associated with a handler NDS by an ext file
|
||||||
|
string extPath;
|
||||||
|
if (!toExtPath(filePath, extPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string ndsRelPath;
|
||||||
|
if (!parseArgFileNds(extPath, ndsRelPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Handler is in EXT_DIR
|
||||||
|
return toAbsPath(ndsRelPath, EXT_DIR, ndsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool argsFillArray(const string& filePath, vector<string>& argarray) {
|
||||||
|
// Ensure argarray is empty
|
||||||
|
argarray.clear();
|
||||||
|
|
||||||
|
if (strCaseEnd(filePath, NDS_EXT)) {
|
||||||
|
string absPath;
|
||||||
|
if (!toAbsPath(filePath, NULL, absPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
argarray.push_back(move(absPath));
|
||||||
|
} else if (strCaseEnd(filePath, ARG_EXT)) {
|
||||||
|
if (!parseArgFileAll(filePath, argarray)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Ensure argv[0] is absolute path
|
||||||
|
string absPath;
|
||||||
|
if (!toAbsPath(argarray[0], NULL, absPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
argarray[0] = absPath;
|
||||||
|
} else {
|
||||||
|
// This is a data file associated with a handler NDS by an ext file
|
||||||
|
string extPath;
|
||||||
|
|
||||||
|
if (!toExtPath(filePath, extPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the arg file for the extension handler
|
||||||
|
if (!parseArgFileAll(extPath, argarray)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extension handler relative path is relative to EXT_DIR, not CWD
|
||||||
|
string absPath;
|
||||||
|
if (!toAbsPath(argarray[0], EXT_DIR, absPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
argarray[0] = absPath;
|
||||||
|
|
||||||
|
// Add the data filename to the end. Its path is relative to CWD.
|
||||||
|
if (!toAbsPath(filePath, NULL, absPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
argarray.push_back(move(absPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return argarray.size() > 0 && strCaseEnd(argarray[0], NDS_EXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> argsGetExtensionList() {
|
||||||
|
vector<string> extensionList;
|
||||||
|
|
||||||
|
// Always supported files: NDS binaries and predefined argument lists
|
||||||
|
extensionList.push_back(NDS_EXT);
|
||||||
|
extensionList.push_back(ARG_EXT);
|
||||||
|
|
||||||
|
// Get a list of extension files: argument lists associated with a file type
|
||||||
|
DIR *dir = opendir (EXT_DIR);
|
||||||
|
if (dir) {
|
||||||
|
for (struct dirent* dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) {
|
||||||
|
// Add the name component of all files ending with EXT_EXT to the list
|
||||||
|
if (dirent->d_type != DT_REG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirent->d_name[0] != '.' && strCaseEnd(dirent->d_name, EXT_EXT)) {
|
||||||
|
size_t extPos = strlen(dirent->d_name) - EXT_EXT.size();
|
||||||
|
dirent->d_name[extPos] = '\0';
|
||||||
|
extensionList.push_back(dirent->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensionList;
|
||||||
|
}
|
47
arm9/source/args.h
Normal file
47
arm9/source/args.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
Copyright (C) 2005 - 2017
|
||||||
|
Michael "Chishm" Chisholm
|
||||||
|
Dave "WinterMute" Murphy
|
||||||
|
Claudio "sverx"
|
||||||
|
Michael "mtheall" Theall
|
||||||
|
|
||||||
|
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 ARGS_H
|
||||||
|
#define ARGS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/* Convert a file path of any type (e.g. .nds or .argv) into a path to the NDS
|
||||||
|
* file to be opened. The returned path may be absolute or relative to the
|
||||||
|
* current working directory.
|
||||||
|
* Returns true on success, false on failure.
|
||||||
|
*/
|
||||||
|
bool argsNdsPath(const std::string& filePath, std::string& ndsPath);
|
||||||
|
|
||||||
|
/* Convert a file path of any type into an argument array by filling the array
|
||||||
|
* that is passed in. The first argument will be the full path to an NDS file.
|
||||||
|
* Returns true on success, false on failure.
|
||||||
|
*/
|
||||||
|
bool argsFillArray(const std::string& filePath, std::vector<std::string>& argarray);
|
||||||
|
|
||||||
|
/* Return a list of all file extensions that can be browsed and opened.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> argsGetExtensionList();
|
||||||
|
|
||||||
|
#endif // ARGS_H
|
5
arm9/source/defaultBanners.s
Normal file
5
arm9/source/defaultBanners.s
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.arm
|
||||||
|
.global hbNoIcon_bin
|
||||||
|
|
||||||
|
hbNoIcon_bin: .incbin "../include/hbNoIcon.bin"
|
||||||
|
|
213
arm9/source/file_browse.cpp
Normal file
213
arm9/source/file_browse.cpp
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
Copyright (C) 2005 - 2017
|
||||||
|
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 "iconTitle.h"
|
||||||
|
|
||||||
|
#define SCREEN_COLS 30
|
||||||
|
#define ENTRIES_PER_SCREEN 20
|
||||||
|
#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 (name.front() == '.') 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
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
vector<DirEntry> dirContents;
|
||||||
|
|
||||||
|
getDirectoryContents (dirContents, extensionList);
|
||||||
|
showDirectoryContents (dirContents, screenOffset);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||||
|
do {
|
||||||
|
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
|
||||||
|
consoleClear();
|
||||||
|
// 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 - 2017
|
||||||
|
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
|
242
arm9/source/iconTitle.cpp
Normal file
242
arm9/source/iconTitle.cpp
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
Copyright (C) 2005 - 2013
|
||||||
|
Michael "Chishm" Chisholm
|
||||||
|
Dave "WinterMute" Murphy
|
||||||
|
Claudio "sverx"
|
||||||
|
Michael "mtheall" Theall
|
||||||
|
|
||||||
|
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 <ctype.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "args.h"
|
||||||
|
#include "hbmenu_banner.h"
|
||||||
|
#include "font6x8.h"
|
||||||
|
|
||||||
|
#define TITLE_POS_X (13*8)
|
||||||
|
#define TITLE_POS_Y (10*8)
|
||||||
|
|
||||||
|
#define ICON_POS_X 26
|
||||||
|
#define ICON_POS_Y 79
|
||||||
|
|
||||||
|
#define TEXT_WIDTH ((22-4)*8/6)
|
||||||
|
|
||||||
|
static int bg2, bg3;
|
||||||
|
static u16 *sprite;
|
||||||
|
static tNDSBanner banner;
|
||||||
|
|
||||||
|
extern tNDSBanner hbNoIcon_bin;
|
||||||
|
|
||||||
|
static inline void writecharRS (int row, int col, u16 car) {
|
||||||
|
// get map pointer
|
||||||
|
u16 *gfx = bgGetMapPtr(bg2);
|
||||||
|
// get old pair of values from VRAM
|
||||||
|
u16 oldval = gfx[row*(512/8/2)+(col/2)];
|
||||||
|
|
||||||
|
// clear the half we will update
|
||||||
|
oldval &= (col%2) ? 0x00FF : 0xFF00;
|
||||||
|
// apply the updated half
|
||||||
|
oldval |= (col%2) ? (car<<8) : car;
|
||||||
|
|
||||||
|
// write back to VRAM
|
||||||
|
gfx[row*(512/8/2)+col/2] = oldval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void writeRow (int rownum, const char* text) {
|
||||||
|
int i,len,p=0;
|
||||||
|
len=strlen(text);
|
||||||
|
|
||||||
|
if (len>TEXT_WIDTH)
|
||||||
|
len=TEXT_WIDTH;
|
||||||
|
|
||||||
|
// clear left part
|
||||||
|
for (i=0;i<(TEXT_WIDTH-len)/2;i++)
|
||||||
|
writecharRS (rownum, i, 0);
|
||||||
|
|
||||||
|
// write centered text
|
||||||
|
for (i=(TEXT_WIDTH-len)/2;i<((TEXT_WIDTH-len)/2+len);i++)
|
||||||
|
writecharRS (rownum, i, text[p++]-' ');
|
||||||
|
|
||||||
|
// clear right part
|
||||||
|
for (i=((TEXT_WIDTH-len)/2+len);i<TEXT_WIDTH;i++)
|
||||||
|
writecharRS (rownum, i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clearIcon (void) { dmaFillHalfWords(0, sprite, sizeof(banner.icon)); }
|
||||||
|
|
||||||
|
void iconTitleInit (void) {
|
||||||
|
// initialize video mode
|
||||||
|
videoSetMode(MODE_4_2D);
|
||||||
|
|
||||||
|
// initialize VRAM banks
|
||||||
|
vramSetBankA(VRAM_A_MAIN_BG);
|
||||||
|
vramSetBankB(VRAM_B_MAIN_SPRITE);
|
||||||
|
|
||||||
|
// initialize bg2 as a rotation background and bg3 as a bmp background
|
||||||
|
// http://mtheall.com/vram.html#T2=3&RNT2=96&MB2=3&TB2=0&S2=2&T3=6&MB3=1&S3=1
|
||||||
|
bg2 = bgInit(2, BgType_Rotation, BgSize_R_512x512, 3, 0);
|
||||||
|
bg3 = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 1, 0);
|
||||||
|
|
||||||
|
// initialize rotate, scale, and scroll
|
||||||
|
bgSetRotateScale(bg3, 0, 1<<8, 1<<8);
|
||||||
|
bgSetScroll(bg3, 0, 0);
|
||||||
|
bgSetRotateScale(bg2, 0, 8*(1<<8)/6, 1<<8);
|
||||||
|
bgSetScroll(bg2, -TITLE_POS_X, -TITLE_POS_Y);
|
||||||
|
|
||||||
|
// clear bg2's map: 512x512 pixels is 64x64 tiles is 4KB
|
||||||
|
dmaFillHalfWords(0, bgGetMapPtr(bg2), 4096);
|
||||||
|
// load compressed font into bg2's tile data
|
||||||
|
decompress(font6x8Tiles, bgGetGfxPtr(bg2), LZ77Vram);
|
||||||
|
|
||||||
|
// load compressed bitmap into bg3
|
||||||
|
decompress(hbmenu_bannerBitmap, bgGetGfxPtr(bg3), LZ77Vram);
|
||||||
|
|
||||||
|
// load font palette
|
||||||
|
dmaCopy(font6x8Pal, BG_PALETTE, font6x8PalLen);
|
||||||
|
|
||||||
|
// apply the bg changes
|
||||||
|
bgUpdate();
|
||||||
|
|
||||||
|
// initialize OAM
|
||||||
|
oamInit(&oamMain, SpriteMapping_1D_128, false);
|
||||||
|
sprite = oamAllocateGfx(&oamMain, SpriteSize_32x32, SpriteColorFormat_16Color);
|
||||||
|
dmaFillHalfWords(0, sprite, sizeof(banner.icon));
|
||||||
|
oamSet(&oamMain, 0, ICON_POS_X, ICON_POS_Y, 0, 0,
|
||||||
|
SpriteSize_32x32, SpriteColorFormat_16Color, sprite,
|
||||||
|
-1, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// oam can only be updated during vblank
|
||||||
|
swiWaitForVBlank();
|
||||||
|
oamUpdate(&oamMain);
|
||||||
|
|
||||||
|
// Load Default Icon.
|
||||||
|
DC_FlushAll();
|
||||||
|
dmaCopy(hbNoIcon_bin.icon, sprite, sizeof(hbNoIcon_bin.icon));
|
||||||
|
dmaCopy(hbNoIcon_bin.palette, SPRITE_PALETTE, sizeof(hbNoIcon_bin.palette));
|
||||||
|
|
||||||
|
// everything's ready :)
|
||||||
|
writeRow (1,"===>>> HBMenu+ <<<===");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadDefaultIcon() {
|
||||||
|
DC_FlushAll();
|
||||||
|
dmaCopy(hbNoIcon_bin.icon, sprite, sizeof(hbNoIcon_bin.icon));
|
||||||
|
dmaCopy(hbNoIcon_bin.palette, SPRITE_PALETTE, sizeof(hbNoIcon_bin.palette));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void iconTitleUpdate (int isdir, const std::string& name) {
|
||||||
|
writeRow (0, name.c_str());
|
||||||
|
writeRow (1, "");
|
||||||
|
writeRow (2, "");
|
||||||
|
writeRow (3, "");
|
||||||
|
|
||||||
|
if (isdir) {
|
||||||
|
// text
|
||||||
|
writeRow (2, "[directory]");
|
||||||
|
// icon
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
} else {
|
||||||
|
std::string ndsPath;
|
||||||
|
if (!argsNdsPath(name, ndsPath)) {
|
||||||
|
writeRow(2, "(invalid argv or NDS file!)");
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Icon_title_offset;
|
||||||
|
|
||||||
|
// open file for reading info
|
||||||
|
FILE *fp = fopen (ndsPath.c_str(), "rb");
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
// text
|
||||||
|
writeRow (2,"(can't open file!)");
|
||||||
|
// icon
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
fclose (fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek (fp, offsetof(tNDSHeader, bannerOffset), SEEK_SET) != 0 || fread (&Icon_title_offset, sizeof(int), 1, fp) != 1) {
|
||||||
|
// text
|
||||||
|
writeRow (2, "(can't read file!)");
|
||||||
|
// icon
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
fclose (fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Icon_title_offset == 0) {
|
||||||
|
// text
|
||||||
|
writeRow (2, "(no title/icon)");
|
||||||
|
// icon
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
fclose (fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek (fp, Icon_title_offset, SEEK_SET) != 0 || fread (&banner, sizeof(banner), 1, fp) != 1) {
|
||||||
|
// text
|
||||||
|
writeRow (2,"(can't read icon/title!)");
|
||||||
|
// icon
|
||||||
|
clearIcon();
|
||||||
|
loadDefaultIcon();
|
||||||
|
fclose (fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close file!
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
// turn unicode into ascii (kind of)
|
||||||
|
// and convert 0x0A into 0x00
|
||||||
|
char *p = (char*)banner.titles[1];
|
||||||
|
int rowOffset = 1;
|
||||||
|
int lineReturns = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(banner.titles[1]); i = i+2) {
|
||||||
|
if ((p[i] == 0x0A) || (p[i] == 0xFF)) {
|
||||||
|
p[i/2] = 0;
|
||||||
|
lineReturns++;
|
||||||
|
} else {
|
||||||
|
p[i/2] = p[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineReturns < 2)rowOffset = 2; // Recenter if bennar has less 2 or less rows of text maintaining empty row gap between nds file name and nds banner.
|
||||||
|
|
||||||
|
// text
|
||||||
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
|
writeRow(i+rowOffset, p);
|
||||||
|
p += strlen(p) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// icon
|
||||||
|
DC_FlushAll();
|
||||||
|
dmaCopy(banner.icon, sprite, sizeof(banner.icon));
|
||||||
|
dmaCopy(banner.palette, SPRITE_PALETTE, sizeof(banner.palette));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
25
arm9/source/iconTitle.h
Normal file
25
arm9/source/iconTitle.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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 <string>
|
||||||
|
|
||||||
|
void iconTitleInit (void);
|
||||||
|
void iconTitleUpdate (int isdir, const std::string& name);
|
280
arm9/source/main.cpp
Normal file
280
arm9/source/main.cpp
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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 <nds/fifocommon.h>
|
||||||
|
#include <nds/fifomessages.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fat.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "args.h"
|
||||||
|
#include "file_browse.h"
|
||||||
|
#include "font.h"
|
||||||
|
#include "hbmenu_consolebg.h"
|
||||||
|
#include "iconTitle.h"
|
||||||
|
#include "skin.h"
|
||||||
|
#include "nds_loader_arm9.h"
|
||||||
|
|
||||||
|
#define BG_256_COLOR (BIT(7))
|
||||||
|
#define FlashBase_S98 0x09000000
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
volatile bool guiEnabled = false;
|
||||||
|
|
||||||
|
void InitGUI(void) {
|
||||||
|
if (guiEnabled)return;
|
||||||
|
guiEnabled = true;
|
||||||
|
iconTitleInit();
|
||||||
|
videoSetModeSub(MODE_4_2D);
|
||||||
|
vramSetBankC(VRAM_C_SUB_BG);
|
||||||
|
int bgSub = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0);
|
||||||
|
PrintConsole *console = consoleInit(0, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 6, false, false);
|
||||||
|
dmaCopy(hbmenu_consolebgBitmap, bgGetGfxPtr(bgSub), 256*256);
|
||||||
|
ConsoleFont font;
|
||||||
|
font.gfx = (u16*)fontTiles;
|
||||||
|
font.pal = (u16*)fontPal;
|
||||||
|
font.numChars = 95;
|
||||||
|
font.numColors = (fontPalLen / 2);
|
||||||
|
font.bpp = 4;
|
||||||
|
font.asciiOffset = 32;
|
||||||
|
font.convertSingleColor = true;
|
||||||
|
consoleSetFont(console, &font);
|
||||||
|
dmaCopy(hbmenu_consolebgPal, BG_PALETTE_SUB, 256*2);
|
||||||
|
BG_PALETTE_SUB[255] = RGB15(31,31,31);
|
||||||
|
keysSetRepeat(25,5);
|
||||||
|
consoleSetWindow(console, 1, 1, 30, 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pixel_SUB(u16* screen, s16 x, s16 y, uint16 palet) {
|
||||||
|
uint16 bgsubAddress, h;
|
||||||
|
|
||||||
|
if (x < 0 || x > 256-1 || y < 0 || y > 192-1)return;
|
||||||
|
|
||||||
|
bgsubAddress = (x>>3)*32 + ((x&7)>>1) + (y>>3)*1024 + ((y&7)<<2);
|
||||||
|
h = screen[bgsubAddress];
|
||||||
|
|
||||||
|
if ((x & 1 ) == 0) {
|
||||||
|
h = palet | (h&0xff00);
|
||||||
|
} else {
|
||||||
|
h = (palet * 0x100) | ( h & 0xff);
|
||||||
|
}
|
||||||
|
screen[bgsubAddress] = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBG(uint16* screen,uint16 color) {
|
||||||
|
int x = 0, y = 0;
|
||||||
|
for(y = 0; y < 192; y++) {
|
||||||
|
for(x = 0; x < 256; x++)screen[(y)*256 + (x)] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearBG_SUB(uint16* screen, uint16 palet) {
|
||||||
|
int x = 0, y = 0;
|
||||||
|
|
||||||
|
for (y = 0; y < 192; y++) {
|
||||||
|
for(x = 0; x < 256; x++)Pixel_SUB(screen, x, y, palet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitGUIForGBA() {
|
||||||
|
|
||||||
|
defaultExceptionHandler();
|
||||||
|
|
||||||
|
u16* MainScreen = VRAM_A;
|
||||||
|
u16* SubScreen = (u16*)BG_TILE_RAM_SUB(1);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vramSetPrimaryBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_SUB_BG, VRAM_D_MAIN_BG);
|
||||||
|
powerOn(POWER_ALL);
|
||||||
|
|
||||||
|
videoSetMode(MODE_FB0 | DISPLAY_BG2_ACTIVE);
|
||||||
|
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE );
|
||||||
|
REG_BG0CNT_SUB = BG_256_COLOR | BG_MAP_BASE(0) | BG_TILE_BASE(1);
|
||||||
|
uint16* map1 = (uint16*)BG_MAP_RAM_SUB(0);
|
||||||
|
for(i=0;i<(256*192/8/8);i++)map1[i]=i;
|
||||||
|
lcdMainOnTop();
|
||||||
|
ClearBG(MainScreen, RGB15(31,31,31));
|
||||||
|
BG_PALETTE_SUB[0] = RGB15(31,31,31);
|
||||||
|
BG_PALETTE_SUB[1] = RGB15(0,0,0);
|
||||||
|
BG_PALETTE_SUB[2] = RGB15(29,0,0);
|
||||||
|
BG_PALETTE_SUB[3] = RGB15(0,20,0);
|
||||||
|
BG_PALETTE_SUB[4] = RGB15(0,31,31);
|
||||||
|
BG_PALETTE_SUB[5] = RGB15(0,0,31);
|
||||||
|
BG_PALETTE_SUB[6] = RGB15(31,31,0);
|
||||||
|
ClearBG_SUB( SubScreen, 0 );
|
||||||
|
swiWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Read_S98NOR_ID() {
|
||||||
|
*((vu16*)(FlashBase_S98)) = 0xF0;
|
||||||
|
*((vu16*)(FlashBase_S98+0x555*2)) = 0xAA;
|
||||||
|
*((vu16*)(FlashBase_S98+0x2AA*2)) = 0x55;
|
||||||
|
*((vu16*)(FlashBase_S98+0x555*2)) = 0x90;
|
||||||
|
return *((vu16*)(FlashBase_S98+0xE*2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetKernelRomPage() {
|
||||||
|
*(vu16*)0x09FE0000 = 0xD200;
|
||||||
|
*(vu16*)0x08000000 = 0x1500;
|
||||||
|
*(vu16*)0x08020000 = 0xD200;
|
||||||
|
*(vu16*)0x08040000 = 0x1500;
|
||||||
|
*(vu16*)0x09880000 = 0x8002; // Kernel section of NorFlash
|
||||||
|
*(vu16*)0x09FC0000 = 0x1500;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gba_frame() {
|
||||||
|
int ret;
|
||||||
|
int x = 0, y = 0;
|
||||||
|
u16 *pDstBuf1;
|
||||||
|
u16 *pDstBuf2;
|
||||||
|
|
||||||
|
if (access("/gbaframe.bmp", F_OK) == 0) {
|
||||||
|
ret = LoadSkin(2, "/gbaframe.bmp");
|
||||||
|
if(ret)return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access("/GBA_SIGN/gbaframe.bmp", F_OK) == 0) {
|
||||||
|
ret = LoadSkin(2, "/GBA_SIGN/gbaframe.bmp");
|
||||||
|
if(ret)return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access("/_system_/gbaframe.bmp", F_OK) == 0) {
|
||||||
|
ret = LoadSkin(2, "/_system_/gbaframe.bmp");
|
||||||
|
if(ret)return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access("/ttmenu/gbaframe.bmp", F_OK) == 0) {
|
||||||
|
ret = LoadSkin(2, "/ttmenu/gbaframe.bmp");
|
||||||
|
if(ret)return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDstBuf1 = (u16*)0x06000000;
|
||||||
|
pDstBuf2 = (u16*)0x06020000;
|
||||||
|
for(y = 0; y < 192; y++) {
|
||||||
|
for(x = 0; x < 256; x++) {
|
||||||
|
pDstBuf1[x] = 0x0000;
|
||||||
|
pDstBuf2[x] = 0x0000;
|
||||||
|
}
|
||||||
|
pDstBuf1 += 256;
|
||||||
|
pDstBuf2 += 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gbaMode() {
|
||||||
|
InitGUIForGBA();
|
||||||
|
|
||||||
|
sysSetCartOwner(true);
|
||||||
|
|
||||||
|
swiWaitForVBlank();
|
||||||
|
|
||||||
|
if (Read_S98NOR_ID() == 0x223D)SetKernelRomPage();
|
||||||
|
|
||||||
|
swiWaitForVBlank();
|
||||||
|
|
||||||
|
videoSetMode(0);
|
||||||
|
videoSetModeSub(0);
|
||||||
|
|
||||||
|
vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_BG, VRAM_C_MAIN_BG, VRAM_D_MAIN_BG);
|
||||||
|
|
||||||
|
if(PersonalData->gbaScreen) { lcdMainOnBottom(); } else { lcdMainOnTop(); }
|
||||||
|
|
||||||
|
gba_frame();
|
||||||
|
|
||||||
|
sysSetCartOwner(false);
|
||||||
|
fifoSendValue32(FIFO_USER_01, 1);
|
||||||
|
REG_IME = 0;
|
||||||
|
while(1)swiWaitForVBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
int stop(void) {
|
||||||
|
while (1) {
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
if (keysDown() != 0)break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileBrowser() {
|
||||||
|
InitGUI();
|
||||||
|
consoleClear();
|
||||||
|
vector<string> extensionList = argsGetExtensionList();
|
||||||
|
chdir("/nds");
|
||||||
|
while(1) {
|
||||||
|
string filename = browseForFile(extensionList);
|
||||||
|
// Construct a command line
|
||||||
|
vector<string> argarray;
|
||||||
|
if (!argsFillArray(filename, argarray)) {
|
||||||
|
printf("Invalid NDS or arg file selected\n");
|
||||||
|
} else {
|
||||||
|
iprintf("Running %s with %d parameters\n", argarray[0].c_str(), argarray.size());
|
||||||
|
// Make a copy of argarray using C strings, for the sake of runNdsFile
|
||||||
|
vector<const char*> c_args;
|
||||||
|
for (const auto& arg: argarray) { c_args.push_back(arg.c_str()); }
|
||||||
|
// Try to run the NDS file with the given arguments
|
||||||
|
int err = runNdsFile(c_args[0], c_args.size(), &c_args[0]);
|
||||||
|
iprintf("Start failed. Error %i\n", err);
|
||||||
|
}
|
||||||
|
argarray.clear();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// overwrite reboot stub identifier
|
||||||
|
// so tapping power on DSi returns to DSi menu
|
||||||
|
extern u64 *fake_heap_end;
|
||||||
|
*fake_heap_end = 0;
|
||||||
|
if (!fatInitDefault()) {
|
||||||
|
InitGUI();
|
||||||
|
consoleClear();
|
||||||
|
printf ("\n\n\n\n\n\n\n\n\n\n FAT init failed! \n");
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
switch (keysDown()) {
|
||||||
|
case KEY_A: {
|
||||||
|
if (!isDSiMode()) { gbaMode(); } else { FileBrowser(); }
|
||||||
|
} break;
|
||||||
|
case KEY_B: FileBrowser(); break;
|
||||||
|
default: {
|
||||||
|
if((access("/r4tf.nds", F_OK) == 0)) {
|
||||||
|
return runNdsFile("/r4tf.nds", 0, NULL);
|
||||||
|
} else if((access("/boot.nds", F_OK) == 0)) {
|
||||||
|
return runNdsFile("/boot.nds", 0, NULL);
|
||||||
|
} else {
|
||||||
|
FileBrowser();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
|
354
arm9/source/nds_loader_arm9.c
Normal file
354
arm9/source/nds_loader_arm9.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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"
|
||||||
|
#include "exceptionstub_bin.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "nds_loader_arm9.h"
|
||||||
|
|
||||||
|
#define TMP_DATA 0x02100000
|
||||||
|
|
||||||
|
#define LCDC_BANK_D (u16*)0x06860000
|
||||||
|
#define STORED_FILE_CLUSTER (*(((u32*)LCDC_BANK_D) + 1))
|
||||||
|
#define INIT_DISC (*(((u32*)LCDC_BANK_D) + 2))
|
||||||
|
#define WANT_TO_PATCH_DLDI (*(((u32*)LCDC_BANK_D) + 3))
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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)return false; // does not have a DLDI section
|
||||||
|
|
||||||
|
pDH = (data_t*)(io_dldi_data);
|
||||||
|
|
||||||
|
pAH = &(binData[patchOffset]);
|
||||||
|
|
||||||
|
if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI)return false; // No DLDI patch
|
||||||
|
|
||||||
|
if (pDH[DO_driverSize] > pAH[DO_allocatedSpace])return false; // Not enough space for patch
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
eRunNdsRetCode 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_D_CR = VRAM_ENABLE | VRAM_D_LCD;
|
||||||
|
// Load the loader/patcher into the correct address
|
||||||
|
vramcpy (LCDC_BANK_D, loader, loaderSize);
|
||||||
|
|
||||||
|
// Set the parameters for the loader
|
||||||
|
// STORED_FILE_CLUSTER = cluster;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, STORED_FILE_CLUSTER_OFFSET, cluster);
|
||||||
|
// INIT_DISC = initDisc;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, INIT_DISC_OFFSET, initDisc);
|
||||||
|
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, DSIMODE_OFFSET, isDSiMode());
|
||||||
|
if(argv[0][0]=='s' && argv[0][1]=='d') {
|
||||||
|
dldiPatchNds = false;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, HAVE_DSISD_OFFSET, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WANT_TO_PATCH_DLDI = dldiPatchNds;
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, WANT_TO_PATCH_DLDI_OFFSET, dldiPatchNds);
|
||||||
|
// Give arguments to loader
|
||||||
|
argStart = (char*)LCDC_BANK_D + readAddr((data_t*)LCDC_BANK_D, 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_D, ARG_START_OFFSET, (addr_t)argStart - (addr_t)LCDC_BANK_D);
|
||||||
|
writeAddr ((data_t*) LCDC_BANK_D, ARG_SIZE_OFFSET, argSize);
|
||||||
|
|
||||||
|
if(dldiPatchNds) {
|
||||||
|
// Patch the loader with a DLDI for the card
|
||||||
|
if (!dldiPatchLoader ((data_t*)LCDC_BANK_D, loaderSize, initDisc))return RUN_NDS_PATCH_DLDI_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqDisable(IRQ_ALL);
|
||||||
|
|
||||||
|
// Give the VRAM to the ARM7
|
||||||
|
VRAM_D_CR = VRAM_ENABLE | VRAM_D_ARM7_0x06020000;
|
||||||
|
// 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(0x06020000);
|
||||||
|
|
||||||
|
swiSoftReset();
|
||||||
|
return RUN_NDS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
eRunNdsRetCode 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 RUN_NDS_STAT_FAILED;
|
||||||
|
|
||||||
|
if (argc <= 0 || !argv) {
|
||||||
|
// Construct a command line if we weren't supplied with one
|
||||||
|
if (!getcwd (filePath, PATH_MAX))return RUN_NDS_GETCWD_FAILED;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void(*exceptionstub)(void) = (void(*)(void))0x2FFA000;
|
||||||
|
|
||||||
|
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;
|
||||||
|
memcpy(exceptionstub,exceptionstub_bin,exceptionstub_bin_size);
|
||||||
|
exceptionstub();
|
||||||
|
DC_FlushAll();
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
50
arm9/source/nds_loader_arm9.h
Normal file
50
arm9/source/nds_loader_arm9.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RUN_NDS_OK = 0,
|
||||||
|
RUN_NDS_STAT_FAILED,
|
||||||
|
RUN_NDS_GETCWD_FAILED,
|
||||||
|
RUN_NDS_PATCH_DLDI_FAILED,
|
||||||
|
} eRunNdsRetCode;
|
||||||
|
|
||||||
|
#define LOAD_DEFAULT_NDS 0
|
||||||
|
|
||||||
|
eRunNdsRetCode runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool dldiPatchNds, int argc, const char** argv);
|
||||||
|
|
||||||
|
eRunNdsRetCode runNdsFile (const char* filename, int argc, const char** argv);
|
||||||
|
|
||||||
|
bool installBootStub(bool havedsiSD);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NDS_LOADER_ARM7_H
|
||||||
|
|
319
arm9/source/skin.cpp
Normal file
319
arm9/source/skin.cpp
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
#include <fat.h>
|
||||||
|
#include <nds.h>
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "skin.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BI_RGB (0)
|
||||||
|
#define BI_RLE8 (1)
|
||||||
|
#define BI_RLE4 (2)
|
||||||
|
#define BI_Bitfields (3)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 bfType[2];
|
||||||
|
u32 bfSize;
|
||||||
|
u16 bfReserved1;
|
||||||
|
u16 bfReserved2;
|
||||||
|
u32 bfOffset;
|
||||||
|
u32 biSize;
|
||||||
|
u32 biWidth;
|
||||||
|
u32 biHeight;
|
||||||
|
u16 biPlanes;
|
||||||
|
u16 biBitCount;
|
||||||
|
u32 biCopmression;
|
||||||
|
u32 biSizeImage;
|
||||||
|
u32 biXPixPerMeter;
|
||||||
|
u32 biYPixPerMeter;
|
||||||
|
u32 biClrUsed;
|
||||||
|
u32 biCirImportant;
|
||||||
|
u8 *pPalette;
|
||||||
|
u8 *pBitmap;
|
||||||
|
u32 DataWidth;
|
||||||
|
} TBMPHeader;
|
||||||
|
|
||||||
|
|
||||||
|
static u16 GetVariable16bit(void *pb) {
|
||||||
|
u16 res;
|
||||||
|
u8 *pb8=(u8*)pb;
|
||||||
|
|
||||||
|
res=(u32)pb8[0] << 0;
|
||||||
|
res+=(u32)pb8[1] << 8;
|
||||||
|
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 GetVariable32bit(void *pb) {
|
||||||
|
u32 res;
|
||||||
|
u8 *pb8=(u8*)pb;
|
||||||
|
|
||||||
|
res=(u32)pb8[0] << 0;
|
||||||
|
res+=(u32)pb8[1] << 8;
|
||||||
|
res+=(u32)pb8[2] << 16;
|
||||||
|
res+=(u32)pb8[3] << 24;
|
||||||
|
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool GetBMPHeader(u8 *pb,TBMPHeader *pBMPHeader) {
|
||||||
|
if(pb==NULL){
|
||||||
|
// BMP_LoadErrorStr="SourceData Null.";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
if(pBMPHeader==NULL){
|
||||||
|
// BMP_LoadErrorStr="pBMPHeader Null.";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pBMPHeader->bfType[0]=pb[0];
|
||||||
|
pBMPHeader->bfType[1]=pb[1];
|
||||||
|
pBMPHeader->bfSize=GetVariable32bit(&pb[2]);
|
||||||
|
pBMPHeader->bfReserved1=GetVariable16bit(&pb[6]);
|
||||||
|
pBMPHeader->bfReserved2=GetVariable16bit(&pb[8]);
|
||||||
|
pBMPHeader->bfOffset=GetVariable32bit(&pb[10]);
|
||||||
|
pBMPHeader->biSize=GetVariable32bit(&pb[14+0]);
|
||||||
|
pBMPHeader->biWidth=GetVariable32bit(&pb[14+4]);
|
||||||
|
pBMPHeader->biHeight=GetVariable32bit(&pb[14+8]);
|
||||||
|
pBMPHeader->biPlanes=GetVariable16bit(&pb[14+12]);
|
||||||
|
pBMPHeader->biBitCount=GetVariable16bit(&pb[14+14]);
|
||||||
|
pBMPHeader->biCopmression=GetVariable32bit(&pb[14+16]);
|
||||||
|
pBMPHeader->biSizeImage=GetVariable32bit(&pb[14+20]);
|
||||||
|
pBMPHeader->biXPixPerMeter=GetVariable32bit(&pb[14+24]);
|
||||||
|
pBMPHeader->biYPixPerMeter=GetVariable32bit(&pb[14+28]);
|
||||||
|
pBMPHeader->biClrUsed=GetVariable32bit(&pb[14+32]);
|
||||||
|
pBMPHeader->biCirImportant=GetVariable32bit(&pb[14+36]);
|
||||||
|
|
||||||
|
pBMPHeader->pPalette=&pb[14+40];
|
||||||
|
pBMPHeader->pBitmap=&pb[pBMPHeader->bfOffset];
|
||||||
|
|
||||||
|
pBMPHeader->DataWidth=0;
|
||||||
|
|
||||||
|
if((pBMPHeader->bfType[0]!='B')||(pBMPHeader->bfType[1]!='M')){
|
||||||
|
// BMP_LoadErrorStr="Error MagicID!=BM";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pBMPHeader->biCopmression!=BI_RGB){
|
||||||
|
// BMP_LoadErrorStr="Error notsupport Compression";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pBMPHeader->biHeight>=0x80000000){
|
||||||
|
// BMP_LoadErrorStr="Error notsupport OS/2 format";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pBMPHeader->biPlanes!=1){
|
||||||
|
// BMP_LoadErrorStr="Error notsupport Planes!=1";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pBMPHeader->biBitCount){
|
||||||
|
case 1:
|
||||||
|
// BMP_LoadErrorStr="Error notsupport 1bitcolor.";
|
||||||
|
return(false);
|
||||||
|
case 4:
|
||||||
|
// BMP_LoadErrorStr="Error notsupport 4bitcolor.";
|
||||||
|
return(false);
|
||||||
|
case 8:
|
||||||
|
pBMPHeader->DataWidth=pBMPHeader->biWidth*1;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
// BMP_LoadErrorStr="Error notsupport 16bitcolor.";
|
||||||
|
return(false);
|
||||||
|
case 24:
|
||||||
|
pBMPHeader->DataWidth=pBMPHeader->biWidth*3;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
pBMPHeader->DataWidth=pBMPHeader->biWidth*4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// BMP_LoadErrorStr="Error Unknown xxBitColor.";
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((pBMPHeader->DataWidth&3)!=0){
|
||||||
|
pBMPHeader->DataWidth+=4-(pBMPHeader->DataWidth&3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BMP_LoadErrorStr="";
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool intLoadBM(const char *bmpfn,u16 *pbm,const u32 bmw,const u32 bmh) {
|
||||||
|
FILE *fh;
|
||||||
|
|
||||||
|
|
||||||
|
// bmerrstr1[0]=0;
|
||||||
|
// bmerrstr2[0]=0;
|
||||||
|
|
||||||
|
if(pbm == NULL) {
|
||||||
|
// snprintf(bmerrstr1,256,"BitmapMemory is NULL.");
|
||||||
|
// snprintf(bmerrstr2,256,"The memory is insufficient?");
|
||||||
|
// _consolePrintf("%s\n",bmerrstr1);
|
||||||
|
// _consolePrintf("%s\n",bmerrstr2);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *bmdata = NULL;
|
||||||
|
u32 bmsize;
|
||||||
|
|
||||||
|
fh=fopen(bmpfn, "rb");
|
||||||
|
|
||||||
|
|
||||||
|
if(fh != NULL) {
|
||||||
|
fseek(fh, 0, SEEK_END);
|
||||||
|
bmsize=ftell(fh);
|
||||||
|
fseek(fh, 0, SEEK_SET);
|
||||||
|
bmdata = (u8*)malloc(bmsize);
|
||||||
|
|
||||||
|
fread(bmdata, 1, bmsize, fh);
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bmdata==NULL){
|
||||||
|
return(false);
|
||||||
|
}/* else {
|
||||||
|
_consolePrintf("loadskin /shell/%s\n",bmpfn);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
TBMPHeader BMPHeader;
|
||||||
|
|
||||||
|
if(!GetBMPHeader(bmdata,&BMPHeader)) {
|
||||||
|
// snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn);
|
||||||
|
// snprintf(bmerrstr2,256,"%s",BMP_LoadErrorStr);
|
||||||
|
// _consolePrintf("%s\n",bmerrstr1);
|
||||||
|
// _consolePrintf("%s\n",bmerrstr2);
|
||||||
|
free(bmdata); bmdata=NULL;
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((BMPHeader.biWidth==1)&&(BMPHeader.biHeight==1)) {
|
||||||
|
free(bmdata);
|
||||||
|
bmdata=NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(BMPHeader.biBitCount==32) {
|
||||||
|
// _consolePrintf("Error. not support 32bit color.");
|
||||||
|
free(bmdata);
|
||||||
|
bmdata=NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((BMPHeader.biWidth<bmw)||(BMPHeader.biHeight<bmh)) {
|
||||||
|
// snprintf(bmerrstr1,256,"Request /shell/%s WindowsBitmapFormat",bmpfn);
|
||||||
|
// snprintf(bmerrstr2,256,"%d x %dpixel 8 or 24bitcolor NoCompression.",bmw,bmh);
|
||||||
|
// _consolePrintf("%s\n",bmerrstr1);
|
||||||
|
// _consolePrintf("%s\n",bmerrstr2);
|
||||||
|
free(bmdata);
|
||||||
|
bmdata=NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 gr=0,gg=0,gb=0;
|
||||||
|
|
||||||
|
#define Gravity(c,cg) { \
|
||||||
|
c+=cg; \
|
||||||
|
cg=c&7; \
|
||||||
|
c=c>>3; \
|
||||||
|
if((c&(~0x1f))!=0) c=(c<0) ? 0x00 : 0x1f; \
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u32 y=0;y<bmh;y++) {
|
||||||
|
u8 *pSrcBM=&BMPHeader.pBitmap[(BMPHeader.biHeight-1-y)*BMPHeader.DataWidth];
|
||||||
|
u16 *pDstBM=&pbm[y*bmw];
|
||||||
|
switch(BMPHeader.biBitCount) {
|
||||||
|
case 8: {
|
||||||
|
u8 *PaletteTable=BMPHeader.pPalette;
|
||||||
|
for(u32 x=0;x<bmw;x++){
|
||||||
|
u8 *pal;
|
||||||
|
u32 r,g,b;
|
||||||
|
|
||||||
|
pal=&PaletteTable[*pSrcBM*4];
|
||||||
|
pSrcBM+=1;
|
||||||
|
|
||||||
|
b=pal[0];
|
||||||
|
g=pal[1];
|
||||||
|
r=pal[2];
|
||||||
|
|
||||||
|
Gravity(b,gb);
|
||||||
|
Gravity(g,gg);
|
||||||
|
Gravity(r,gr);
|
||||||
|
|
||||||
|
pDstBM[x]=RGB15(r,g,b) | BIT(15);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 24: {
|
||||||
|
for(u32 x=0;x<bmw;x++) {
|
||||||
|
u32 r,g,b;
|
||||||
|
|
||||||
|
b=pSrcBM[0];
|
||||||
|
g=pSrcBM[1];
|
||||||
|
r=pSrcBM[2];
|
||||||
|
pSrcBM+=3;
|
||||||
|
|
||||||
|
Gravity(b,gb);
|
||||||
|
Gravity(g,gg);
|
||||||
|
Gravity(r,gr);
|
||||||
|
|
||||||
|
pDstBM[x]=RGB15(r,g,b) | BIT(15);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef Gravity
|
||||||
|
|
||||||
|
free(bmdata);
|
||||||
|
bmdata=NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ALIGN(4) static u16 *pBuf;
|
||||||
|
|
||||||
|
bool LoadSkin(int mod, const char *Name) {
|
||||||
|
|
||||||
|
u16 *pDstBuf1;
|
||||||
|
u16 *pDstBuf2;
|
||||||
|
|
||||||
|
pBuf = (u16*)malloc(256*192*2);
|
||||||
|
if(!intLoadBM(Name, pBuf, 256, 192)) { free(pBuf); return false; }
|
||||||
|
|
||||||
|
switch (mod) {
|
||||||
|
case 0: pDstBuf1 = (u16*)0x06020000; break;
|
||||||
|
case 1: pDstBuf1 = (u16*)0x06220000; break;
|
||||||
|
case 2:
|
||||||
|
pDstBuf1 = (u16*)0x06000000;
|
||||||
|
pDstBuf2 = (u16*)0x06020000;
|
||||||
|
// pDstBuf1 = (u16*)0x06800000;
|
||||||
|
// pDstBuf2 = (u16*)0x06820000;
|
||||||
|
break;
|
||||||
|
default: pDstBuf1 = (u16*)0x06020000; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(s32 y=0;y<192;y++) {
|
||||||
|
for(s32 x=0;x<256;x++) {
|
||||||
|
pDstBuf1[x]=pBuf[x];
|
||||||
|
if(mod == 2)pDstBuf2[x]=pBuf[x];
|
||||||
|
}
|
||||||
|
pDstBuf1+=256;
|
||||||
|
if(mod == 2)pDstBuf2+=256;
|
||||||
|
pBuf+=256;
|
||||||
|
}
|
||||||
|
|
||||||
|
// free(pBuf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
10
arm9/source/skin.h
Normal file
10
arm9/source/skin.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern bool LoadSkin(int mod, const char *Name);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#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:
|
18
license.txt
Normal file
18
license.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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, US
|
3
ndsbootloader/.gitignore
vendored
Normal file
3
ndsbootloader/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*build
|
||||||
|
load.bin
|
||||||
|
load.elf
|
123
ndsbootloader/Makefile
Normal file
123
ndsbootloader/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 -Wl,-g $(ARCH) -Wl,-Map,$(TARGET).map
|
||||||
|
|
||||||
|
LIBS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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)/$(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
ndsbootloader/arm9code/mpu_reset.s
Normal file
110
ndsbootloader/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
ndsbootloader/load.ld
Normal file
198
ndsbootloader/load.ld
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
|
||||||
|
vram : ORIGIN = 0x06020000, LENGTH = 64K
|
||||||
|
}
|
||||||
|
|
||||||
|
__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
ndsbootloader/source/arm7clear.s
Normal file
70
ndsbootloader/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
|
||||||
|
|
70
ndsbootloader/source/arm9clear.arm.c
Normal file
70
ndsbootloader/source/arm9clear.arm.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
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
ndsbootloader/source/arm9mpu_reset.s
Normal file
6
ndsbootloader/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
ndsbootloader/source/bios.s
Normal file
13
ndsbootloader/source/bios.s
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.global swiDelay
|
||||||
|
.thumb_func
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swiDelay:
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swi 0x03
|
||||||
|
bx lr
|
379
ndsbootloader/source/boot.c
Normal file
379
ndsbootloader/source/boot.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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>
|
||||||
|
#include <nds/memory.h>
|
||||||
|
#include <nds/arm7/audio.h>
|
||||||
|
#include "fat.h"
|
||||||
|
#include "dldi_patcher.h"
|
||||||
|
#include "card.h"
|
||||||
|
#include "boot.h"
|
||||||
|
#include "sdmmc.h"
|
||||||
|
|
||||||
|
void arm7clearRAM();
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Important things
|
||||||
|
#define TEMP_MEM 0x02FFD000
|
||||||
|
#define TWL_HEAD 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;
|
||||||
|
extern unsigned long dsiMode;
|
||||||
|
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
static char boot_nds[] = "fat:/boot.nds";
|
||||||
|
static unsigned long argbuf[4];
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
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) {
|
||||||
|
|
||||||
|
char *arg = boot_nds;
|
||||||
|
argSize = __builtin_strlen(boot_nds);
|
||||||
|
|
||||||
|
if (dsiSD) {
|
||||||
|
arg++;
|
||||||
|
arg[0] = 's';
|
||||||
|
arg[1] = 'd';
|
||||||
|
}
|
||||||
|
__builtin_memcpy(argbuf,arg,argSize+1);
|
||||||
|
argSrc = argbuf;
|
||||||
|
} else {
|
||||||
|
argSrc = (u32*)(argStart + (int)&_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ARM9_DST == 0 && ARM9_LEN == 0) {
|
||||||
|
ARM9_DST = *((u32*)(NDS_HEAD + 0x038));
|
||||||
|
ARM9_LEN = *((u32*)(NDS_HEAD + 0x03C));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned
|
||||||
|
|
||||||
|
if (dsiMode && (*(u8*)(NDS_HEAD + 0x012) & BIT(1)))
|
||||||
|
{
|
||||||
|
u32 ARM9i_DST = *((u32*)(TWL_HEAD + 0x1C8));
|
||||||
|
u32 ARM9i_LEN = *((u32*)(TWL_HEAD + 0x1CC));
|
||||||
|
if (ARM9i_LEN)
|
||||||
|
{
|
||||||
|
u32* argDst2 = (u32*)((ARM9i_DST + ARM9i_LEN + 3) & ~3); // Word aligned
|
||||||
|
if (argDst2 > argDst)
|
||||||
|
argDst = argDst2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
((vu32*)0x040044f0)[2] = 0x202DDD1D;
|
||||||
|
((vu32*)0x040044f0)[3] = 0xE1A00005;
|
||||||
|
while((*(vu32*)0x04004400) & 0x2000000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (dsiMode && (ndsHeader[0x10>>2]&BIT(16+1)))
|
||||||
|
{
|
||||||
|
// Read full TWL header
|
||||||
|
fileRead((char*)TWL_HEAD, fileCluster, 0, 0x1000);
|
||||||
|
|
||||||
|
u32 ARM9i_SRC = *(u32*)(TWL_HEAD+0x1C0);
|
||||||
|
char* ARM9i_DST = (char*)*(u32*)(TWL_HEAD+0x1C8);
|
||||||
|
u32 ARM9i_LEN = *(u32*)(TWL_HEAD+0x1CC);
|
||||||
|
u32 ARM7i_SRC = *(u32*)(TWL_HEAD+0x1D0);
|
||||||
|
char* ARM7i_DST = (char*)*(u32*)(TWL_HEAD+0x1D8);
|
||||||
|
u32 ARM7i_LEN = *(u32*)(TWL_HEAD+0x1DC);
|
||||||
|
|
||||||
|
if (ARM9i_LEN)
|
||||||
|
fileRead(ARM9i_DST, fileCluster, ARM9i_SRC, ARM9i_LEN);
|
||||||
|
if (ARM7i_LEN)
|
||||||
|
fileRead(ARM7i_DST, fileCluster, ARM7i_SRC, ARM7i_LEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
#ifndef NO_SDMMC
|
||||||
|
int sdmmc_sd_readsectors(u32 sector_no, u32 numsectors, void *out);
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Main function
|
||||||
|
bool sdmmc_inserted() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sdmmc_startup() {
|
||||||
|
sdmmc_controller_init(true);
|
||||||
|
return sdmmc_sdcard_init() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sdmmc_readsectors(u32 sector_no, u32 numsectors, void *out) {
|
||||||
|
return sdmmc_sdcard_readsectors(sector_no, numsectors, out) == 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void mpu_reset();
|
||||||
|
void mpu_reset_end();
|
||||||
|
|
||||||
|
int main (void) {
|
||||||
|
#ifdef NO_DLDI
|
||||||
|
dsiSD = true;
|
||||||
|
dsiMode = true;
|
||||||
|
#endif
|
||||||
|
#ifndef NO_SDMMC
|
||||||
|
if (dsiSD && dsiMode) {
|
||||||
|
_io_dldi.fn_readSectors = sdmmc_readsectors;
|
||||||
|
_io_dldi.fn_isInserted = sdmmc_inserted;
|
||||||
|
_io_dldi.fn_startup = sdmmc_startup;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
u32 fileCluster = storedFileCluster;
|
||||||
|
// Init card
|
||||||
|
if(!FAT_InitFiles(initDisc))return -1;
|
||||||
|
/* Invalid file cluster specified */
|
||||||
|
if ((fileCluster < CLUSTER_FIRST) || (fileCluster >= CLUSTER_EOF))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);
|
||||||
|
|
||||||
|
// ARM9 sets up mpu
|
||||||
|
// copy ARM9 function to RAM, and make the ARM9 jump to it
|
||||||
|
copyLoop((void*)TEMP_MEM, (void*)mpu_reset, mpu_reset_end - mpu_reset);
|
||||||
|
(*(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);
|
||||||
|
|
||||||
|
#ifndef NO_DLDI
|
||||||
|
// Patch with DLDI if desired
|
||||||
|
if (wantToPatchDLDI) {
|
||||||
|
dldiPatchBinary ((u8*)((u32*)NDS_HEAD)[0x0A], ((u32*)NDS_HEAD)[0x0B]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_SDMMC
|
||||||
|
if (dsiSD && dsiMode) {
|
||||||
|
sdmmc_controller_init(true);
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFDu;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDDu;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Pass command line arguments to loaded program
|
||||||
|
passArgs_ARM7();
|
||||||
|
|
||||||
|
startBinary_ARM7();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
10
ndsbootloader/source/boot.h
Normal file
10
ndsbootloader/source/boot.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _BOOT_H_
|
||||||
|
#define _BOOT_H_
|
||||||
|
|
||||||
|
#define resetMemory2_ARM9_size 0x400
|
||||||
|
void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_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
ndsbootloader/source/card.h
Normal file
45
ndsbootloader/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
ndsbootloader/source/disc_io.h
Normal file
82
ndsbootloader/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
|
223
ndsbootloader/source/dldi_patcher.c
Normal file
223
ndsbootloader/source/dldi_patcher.c
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings are stored with bit 0x20 flipped (case inverted) to prevent accidental DLDI patching of them
|
||||||
|
#define DLDI_MAGIC_LEN 12
|
||||||
|
#define DLDI_MAGIC_MANGLE_VALUE 0x20
|
||||||
|
static const data_t dldiMagicStringMangled[DLDI_MAGIC_LEN] = "\xCD\x85\xAD\x9F\0cHISHM"; // Normal DLDI file
|
||||||
|
|
||||||
|
// Demangle the magic string by XORing every byte with 0x20, except the NULL terminator
|
||||||
|
static void demangleMagicString(data_t *dest, const data_t *src) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memcpy(dest, src, DLDI_MAGIC_LEN);
|
||||||
|
for (i = 0; i < DLDI_MAGIC_LEN - 1; ++i) {
|
||||||
|
dest[i] ^= DLDI_MAGIC_MANGLE_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEVICE_TYPE_DLDI 0x49444C44
|
||||||
|
|
||||||
|
extern data_t _dldi_start[];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
data_t dldiMagicString[DLDI_MAGIC_LEN];
|
||||||
|
size_t dldiFileSize = 0;
|
||||||
|
|
||||||
|
// Find the DLDI reserved space in the file
|
||||||
|
demangleMagicString(dldiMagicString, dldiMagicStringMangled);
|
||||||
|
patchOffset = quickFind (binData, dldiMagicString, binSize, sizeof(dldiMagicString));
|
||||||
|
|
||||||
|
if (patchOffset < 0) {
|
||||||
|
// does not have a DLDI section
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDH = _dldi_start;
|
||||||
|
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
ndsbootloader/source/dldi_patcher.h
Normal file
32
ndsbootloader/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
|
592
ndsbootloader/source/fat.c
Normal file
592
ndsbootloader/source/fat.c
Normal file
@ -0,0 +1,592 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
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__))
|
||||||
|
|
||||||
|
// BIOS Parameter Block
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
u16 bytesPerSector;
|
||||||
|
u8 sectorsPerCluster;
|
||||||
|
u16 reservedSectors;
|
||||||
|
u8 numFATs;
|
||||||
|
u16 rootEntries;
|
||||||
|
u16 numSectorsSmall;
|
||||||
|
u8 mediaDesc;
|
||||||
|
u16 sectorsPerFAT;
|
||||||
|
u16 sectorsPerTrk;
|
||||||
|
u16 numHeads;
|
||||||
|
u32 numHiddenSectors;
|
||||||
|
u32 numSectors;
|
||||||
|
} __PACKED BIOS_BPB;
|
||||||
|
|
||||||
|
// Boot Sector - must be packed
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 jmpBoot[3];
|
||||||
|
u8 OEMName[8];
|
||||||
|
BIOS_BPB bpb;
|
||||||
|
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];
|
||||||
|
} __PACKED 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];
|
||||||
|
} __PACKED fat32;
|
||||||
|
} __PACKED extBlock;
|
||||||
|
|
||||||
|
__PACKED u16 bootSig;
|
||||||
|
|
||||||
|
} __PACKED BOOT_SEC;
|
||||||
|
|
||||||
|
// _Static_assert(sizeof(BOOT_SEC) == 512);
|
||||||
|
|
||||||
|
// 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->bpb.sectorsPerFAT != 0)
|
||||||
|
{
|
||||||
|
discSecPerFAT = bootSec->bpb.sectorsPerFAT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
discSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootSec->bpb.numSectorsSmall != 0)
|
||||||
|
{
|
||||||
|
discNumSec = bootSec->bpb.numSectorsSmall;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
discNumSec = bootSec->bpb.numSectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
discBytePerSec = BYTES_PER_SECTOR; // Sector size is redefined to be 512 bytes
|
||||||
|
discSecPerClus = bootSec->bpb.sectorsPerCluster * bootSec->bpb.bytesPerSector / BYTES_PER_SECTOR;
|
||||||
|
discBytePerClus = discBytePerSec * discSecPerClus;
|
||||||
|
discFAT = bootSector + bootSec->bpb.reservedSectors;
|
||||||
|
|
||||||
|
discRootDir = discFAT + (bootSec->bpb.numFATs * discSecPerFAT);
|
||||||
|
discData = discRootDir + ((bootSec->bpb.rootEntries * sizeof(DIR_ENT)) / BYTES_PER_SECTOR);
|
||||||
|
|
||||||
|
if ((discNumSec - discData) / bootSec->bpb.sectorsPerCluster < 4085)
|
||||||
|
{
|
||||||
|
discFileSystem = FS_FAT12;
|
||||||
|
}
|
||||||
|
else if ((discNumSec - discData) / bootSec->bpb.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
ndsbootloader/source/fat.h
Normal file
46
ndsbootloader/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
ndsbootloader/source/io_dldi.h
Normal file
44
ndsbootloader/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
ndsbootloader/source/io_dldi.s
Normal file
124
ndsbootloader/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 -- 32 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 0x1a @ 32KiB @ Log [base-2] of the size of this driver in bytes.
|
||||||
|
.byte 0x00 @ Sections to fix
|
||||||
|
.byte 0x1a @ 32KiB @ Log [base-2] of the allocated space in bytes.
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ Text identifier - can be anything up to 47 chars + terminating null -- 32 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 + 32768) - . @ Fill to 32KiB
|
||||||
|
|
||||||
|
_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
|
147
ndsbootloader/source/load_crt0.s
Normal file
147
ndsbootloader/source/load_crt0.s
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
.global dsiMode
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.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
|
||||||
|
dsiMode:
|
||||||
|
.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
|
||||||
|
@---------------------------------------------------------------------------------
|
242
ndsbootloader/source/sdmmc.c
Normal file
242
ndsbootloader/source/sdmmc.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
#ifndef NO_SDMMC
|
||||||
|
#include <nds/bios.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "sdmmc.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);
|
||||||
|
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);
|
||||||
|
volatile uint16_t ctl32 = sdmmc_read16(REG_SDDATACTL32);
|
||||||
|
if((ctl32 & 0x100))
|
||||||
|
{
|
||||||
|
if(readdata) {
|
||||||
|
if(useBuf) {
|
||||||
|
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
||||||
|
if(size > 0x1FF) {
|
||||||
|
if(useBuf32) {
|
||||||
|
for(i = 0; i<0x200; i+=4) {
|
||||||
|
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0; i<0x200; i+=2) {
|
||||||
|
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size -= 0x200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_mask16(REG_SDDATACTL32, 0x800, 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;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL32) |= 0x402u;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL) = (*(vu16*)(SDMMC_BASE + REG_SDDATACTL) & 0xFFDD) | 2;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFFu;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDFu;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 512;
|
||||||
|
*(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;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x20;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EE;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN) = 512;
|
||||||
|
*(vu16*)(SDMMC_BASE + REG_SDSTOP) = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
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);
|
||||||
|
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||||
|
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||||
|
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||||
|
deviceSD.data = out;
|
||||||
|
deviceSD.size = numsectors << 9;
|
||||||
|
sdmmc_send_command(&deviceSD,0x33C12,sector_no);
|
||||||
|
return geterror(&deviceSD);
|
||||||
|
}
|
||||||
|
#endif
|
194
ndsbootloader/source/sdmmc.h
Normal file
194
ndsbootloader/source/sdmmc.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#ifndef __SDMMC_H__
|
||||||
|
#define __SDMMC_H__
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
|
||||||
|
#define DATA32_SUPPORT
|
||||||
|
|
||||||
|
#define SDMMC_BASE 0x04004800
|
||||||
|
|
||||||
|
|
||||||
|
#define REG_SDCMD 0x00
|
||||||
|
#define REG_SDPORTSEL 0x02
|
||||||
|
#define REG_SDCMDARG 0x04
|
||||||
|
#define REG_SDCMDARG0 0x04
|
||||||
|
#define REG_SDCMDARG1 0x06
|
||||||
|
#define REG_SDSTOP 0x08
|
||||||
|
#define REG_SDRESP 0x0c
|
||||||
|
#define REG_SDBLKCOUNT 0x0a
|
||||||
|
|
||||||
|
#define REG_SDRESP0 0x0c
|
||||||
|
#define REG_SDRESP1 0x0e
|
||||||
|
#define REG_SDRESP2 0x10
|
||||||
|
#define REG_SDRESP3 0x12
|
||||||
|
#define REG_SDRESP4 0x14
|
||||||
|
#define REG_SDRESP5 0x16
|
||||||
|
#define REG_SDRESP6 0x18
|
||||||
|
#define REG_SDRESP7 0x1a
|
||||||
|
|
||||||
|
#define REG_SDSTATUS0 0x1c
|
||||||
|
#define REG_SDSTATUS1 0x1e
|
||||||
|
|
||||||
|
#define REG_SDIRMASK0 0x20
|
||||||
|
#define REG_SDIRMASK1 0x22
|
||||||
|
#define REG_SDCLKCTL 0x24
|
||||||
|
|
||||||
|
#define REG_SDBLKLEN 0x26
|
||||||
|
#define REG_SDOPT 0x28
|
||||||
|
#define REG_SDFIFO 0x30
|
||||||
|
|
||||||
|
#define REG_SDDATACTL 0xd8
|
||||||
|
#define REG_SDRESET 0xe0
|
||||||
|
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||||
|
|
||||||
|
#define REG_SDDATACTL32 0x100
|
||||||
|
#define REG_SDBLKLEN32 0x104
|
||||||
|
#define REG_SDBLKCOUNT32 0x108
|
||||||
|
#define REG_SDFIFO32 0x10C
|
||||||
|
|
||||||
|
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||||
|
#define REG_RESET_SDIO 0x1e0
|
||||||
|
//The below defines are from linux kernel drivers/mmc tmio_mmc.h.
|
||||||
|
/* Definitions for values the CTRL_STATUS register can take. */
|
||||||
|
#define TMIO_STAT0_CMDRESPEND 0x0001
|
||||||
|
#define TMIO_STAT0_DATAEND 0x0004
|
||||||
|
#define TMIO_STAT0_CARD_REMOVE 0x0008
|
||||||
|
#define TMIO_STAT0_CARD_INSERT 0x0010
|
||||||
|
#define TMIO_STAT0_SIGSTATE 0x0020
|
||||||
|
#define TMIO_STAT0_WRPROTECT 0x0080
|
||||||
|
#define TMIO_STAT0_CARD_REMOVE_A 0x0100
|
||||||
|
#define TMIO_STAT0_CARD_INSERT_A 0x0200
|
||||||
|
#define TMIO_STAT0_SIGSTATE_A 0x0400
|
||||||
|
|
||||||
|
#define TMIO_STAT1_CMD_IDX_ERR 0x0001
|
||||||
|
#define TMIO_STAT1_CRCFAIL 0x0002
|
||||||
|
#define TMIO_STAT1_STOPBIT_ERR 0x0004
|
||||||
|
#define TMIO_STAT1_DATATIMEOUT 0x0008
|
||||||
|
#define TMIO_STAT1_RXOVERFLOW 0x0010
|
||||||
|
#define TMIO_STAT1_TXUNDERRUN 0x0020
|
||||||
|
#define TMIO_STAT1_CMDTIMEOUT 0x0040
|
||||||
|
#define TMIO_STAT1_RXRDY 0x0100
|
||||||
|
#define TMIO_STAT1_TXRQ 0x0200
|
||||||
|
#define TMIO_STAT1_ILL_FUNC 0x2000
|
||||||
|
#define TMIO_STAT1_CMD_BUSY 0x4000
|
||||||
|
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
||||||
|
|
||||||
|
#define SDMC_NORMAL 0x00000000
|
||||||
|
#define SDMC_ERR_COMMAND 0x00000001
|
||||||
|
#define SDMC_ERR_CRC 0x00000002
|
||||||
|
#define SDMC_ERR_END 0x00000004
|
||||||
|
#define SDMC_ERR_TIMEOUT 0x00000008
|
||||||
|
#define SDMC_ERR_FIFO_OVF 0x00000010
|
||||||
|
#define SDMC_ERR_FIFO_UDF 0x00000020
|
||||||
|
#define SDMC_ERR_WP 0x00000040
|
||||||
|
#define SDMC_ERR_ABORT 0x00000080
|
||||||
|
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
|
||||||
|
#define SDMC_ERR_PARAM 0x00000200
|
||||||
|
#define SDMC_ERR_R1_STATUS 0x00000800
|
||||||
|
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
|
||||||
|
#define SDMC_ERR_RESET 0x00002000
|
||||||
|
#define SDMC_ERR_ILA 0x00004000
|
||||||
|
#define SDMC_ERR_INFO_DETECT 0x00008000
|
||||||
|
|
||||||
|
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
|
||||||
|
#define SDMC_STAT_ERR_CC 0x00100000
|
||||||
|
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
|
||||||
|
#define SDMC_STAT_ERR_CRC 0x00800000
|
||||||
|
#define SDMC_STAT_ERR_OTHER 0xf9c70008
|
||||||
|
|
||||||
|
#define TMIO_MASK_ALL 0x837f031d
|
||||||
|
|
||||||
|
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
||||||
|
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||||
|
|
||||||
|
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
||||||
|
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||||
|
|
||||||
|
typedef struct mmcdevice {
|
||||||
|
u8* data;
|
||||||
|
u32 size;
|
||||||
|
u32 error;
|
||||||
|
u16 stat0;
|
||||||
|
u16 stat1;
|
||||||
|
u32 ret[4];
|
||||||
|
u32 initarg;
|
||||||
|
u32 isSDHC;
|
||||||
|
u32 clk;
|
||||||
|
u32 SDOPT;
|
||||||
|
u32 devicenumber;
|
||||||
|
u32 total_size; //size in sectors of the device
|
||||||
|
u32 res;
|
||||||
|
} mmcdevice;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MMC_DEVICE_SDCARD,
|
||||||
|
MMC_DEVICE_NAND,
|
||||||
|
};
|
||||||
|
|
||||||
|
void sdmmc_controller_init(bool force_init);
|
||||||
|
void sdmmc_initirq();
|
||||||
|
int sdmmc_cardinserted();
|
||||||
|
|
||||||
|
int sdmmc_sdcard_init();
|
||||||
|
int sdmmc_nand_init();
|
||||||
|
void sdmmc_get_cid(int devicenumber, u32 *cid);
|
||||||
|
|
||||||
|
static inline void sdmmc_nand_cid( u32 *cid) {
|
||||||
|
sdmmc_get_cid(MMC_DEVICE_NAND,cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sdmmc_sdcard_cid( u32 *cid) {
|
||||||
|
sdmmc_get_cid(MMC_DEVICE_SDCARD,cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out);
|
||||||
|
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, void *in);
|
||||||
|
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, void *out);
|
||||||
|
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, void *in);
|
||||||
|
|
||||||
|
extern u32 sdmmc_cid[];
|
||||||
|
extern int sdmmc_curdevice;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline u16 sdmmc_read16(u16 reg) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
return *(vu16*)(SDMMC_BASE + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline void sdmmc_write16(u16 reg, u16 val) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
*(vu16*)(SDMMC_BASE + reg) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline u32 sdmmc_read32(u16 reg) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
return *(vu32*)(SDMMC_BASE + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline void sdmmc_write32(u16 reg, u32 val) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
*(vu32*)(SDMMC_BASE + reg) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline void sdmmc_mask16(u16 reg, u16 clear, u16 set) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
u16 val = sdmmc_read16(reg);
|
||||||
|
val &= ~clear;
|
||||||
|
val |= set;
|
||||||
|
sdmmc_write16(reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline void setckl(u32 data) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
|
||||||
|
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
|
||||||
|
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
BIN
r4tfv3.dldi
Normal file
BIN
r4tfv3.dldi
Normal file
Binary file not shown.
BIN
resources/hbmenu_banner.xcf
Normal file
BIN
resources/hbmenu_banner.xcf
Normal file
Binary file not shown.
6
testfiles/test1.argv
Normal file
6
testfiles/test1.argv
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# This is a comment
|
||||||
|
# This is a straightforward command line, name of nds file followed by parameters
|
||||||
|
# this can include a path relative to the .argv file
|
||||||
|
# absolute paths are not currently supported
|
||||||
|
|
||||||
|
argvTest.nds bunch of parameters go here
|
22
testfiles/test2.argv
Normal file
22
testfiles/test2.argv
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# This is a comment
|
||||||
|
# lines consisting only of whitespace will also be ignored
|
||||||
|
# commands can be placed on multiple lines
|
||||||
|
# first the name of the nds file to run
|
||||||
|
# this can include a path relative to the .argv file
|
||||||
|
# absolute paths are not currently supported
|
||||||
|
|
||||||
|
argvTest.nds
|
||||||
|
|
||||||
|
# a single argument
|
||||||
|
argument1
|
||||||
|
|
||||||
|
# multiple arguments separated by spaces
|
||||||
|
argument2 argument3
|
||||||
|
|
||||||
|
# multiple arguments separated by tabs
|
||||||
|
argument4 argument5
|
||||||
|
|
||||||
|
# or even separated by both tabs and spaces
|
||||||
|
argument6 argument7 argument8
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user