mirror of
https://github.com/ApacheThunder/XuluMenu.git
synced 2025-06-18 11:35:42 -04:00
Initial Release Commit...
* Initial version.
This commit is contained in:
parent
5b8838ee53
commit
d9547241d3
54
.gitignore
vendored
Normal file
54
.gitignore
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# devkitARM/libnds/3DS compiled stuff
|
||||
*.bin
|
||||
*.tmd
|
||||
*.cia
|
||||
*.cmd
|
||||
*.nds
|
||||
*.app
|
||||
*.arm7
|
||||
*.arm9
|
||||
*.elf
|
||||
build
|
||||
data
|
||||
|
||||
# Stuff used to build custom banner/misc other things that shouldn't be in repo.
|
||||
title/
|
||||
updator/
|
||||
|
||||
# Stuff generated by Windows.
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
58
Makefile
Normal file
58
Makefile
Normal file
@ -0,0 +1,58 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
export TARGET := xulumenu
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
include $(DEVKITARM)/ds_rules
|
||||
|
||||
.PHONY: data bootloader bootloaderalt clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(TARGET).nds
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
checkarm7:
|
||||
$(MAKE) -C arm7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
checkarm9:
|
||||
$(MAKE) -C arm9
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||
@ndstool -c $@ -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||
-h 0x200 -t nrio-banner.bin
|
||||
@dlditool nrio.dldi $@
|
||||
|
||||
data:
|
||||
@mkdir -p data
|
||||
|
||||
bootloader: data
|
||||
$(MAKE) -C bootloader LOADBIN=$(TOPDIR)/data/load.bin
|
||||
|
||||
bootloaderalt: data
|
||||
$(MAKE) -C bootloaderalt LOADBIN=$(TOPDIR)/data/loadAlt.bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
arm7/$(TARGET).elf:
|
||||
$(MAKE) -C arm7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
arm9/$(TARGET).elf: bootloader bootloaderalt
|
||||
$(MAKE) -C arm9
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
$(MAKE) -C arm9 clean
|
||||
$(MAKE) -C arm7 clean
|
||||
$(MAKE) -C bootloader clean
|
||||
$(MAKE) -C bootloaderalt clean
|
||||
rm -rf data
|
||||
rm -f $(TARGET).nds
|
42
README.md
Normal file
42
README.md
Normal file
@ -0,0 +1,42 @@
|
||||
# XuluMenu
|
||||
|
||||
N-Card (and clones) Universal Loader
|
||||
|
||||
[URL TO BE ADDED LATER]
|
||||
|
||||
This is a custom udisk replacement for the N-Card and it's clones. This version requires flashing to the cart via usb.
|
||||
|
||||
This will simply launch `BOOT.NDS` homebrew on the root of the NAND. A fall back file browsing UI is added if boot.nds is missing or if B button is held on boot.
|
||||
|
||||
### Flashing instructions
|
||||
|
||||
1. Ensure your cart had previously been updated to udisk 1.45 and is formatted to be work with udisk 1.45 and the 1.45 matching DLDI driver.
|
||||
2. Find and connect a DS/DS Lite with GBA slot2 writer device for your N-card/clone to PC.
|
||||
3. Boot up DS and boot the game while holding [L + R + A + B + DPad Up] at the same time until you see "USB SAFE BLOCK" text on bottom screen.
|
||||
4. Run the included UPDATE_ALL.cmd file to have USB exe flash the new SRL to the cart.
|
||||
5. After the process is complete, reboot and see your changes live! File browser will come up if boot.nds is not present or if cart is booted with B button held.
|
||||
|
||||
### License
|
||||
|
||||
Major portions of this code are licensed under GPL-2.0-or-later (particularly, nds-bootloader and nds_loader_arm9.)
|
||||
```
|
||||
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.
|
||||
```
|
||||
|
||||
All other source code files are licensed under the 0BSD license.
|
122
arm7/Makefile
Normal file
122
arm7/Makefile
Normal file
@ -0,0 +1,122 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.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 -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -Os\
|
||||
$(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
|
||||
#---------------------------------------------------------------------------------------
|
32
arm7/source/main.c
Normal file
32
arm7/source/main.c
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
DSXulu
|
||||
DS-Xtreme Universal Loader
|
||||
By lifehackerhansol
|
||||
|
||||
SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <nds.h>
|
||||
|
||||
void VblankHandler(void) {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
ledBlink(0);
|
||||
|
||||
irqInit();
|
||||
fifoInit();
|
||||
installSystemFIFO();
|
||||
irqSet(IRQ_VBLANK, VblankHandler);
|
||||
irqEnable(IRQ_VBLANK);
|
||||
|
||||
while(1) {
|
||||
swiWaitForVBlank();
|
||||
|
||||
if(fifoCheckValue32(FIFO_USER_01)) {
|
||||
fifoGetValue32(FIFO_USER_01);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
137
arm9/Makefile
Normal file
137
arm9/Makefile
Normal file
@ -0,0 +1,137 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.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 -march=armv5te -mtune=arm946e-s
|
||||
|
||||
CFLAGS := -g -Wall -Os \
|
||||
$(ARCH) $(INCLUDE) -DARM9 -D_NO_BOOTSTUB_
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,--defsym,__secure_area__=0 -Wl,--section-start,.crt0=0x02000000,-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
|
||||
#---------------------------------------------------------------------------------------
|
BIN
arm9/binaries/udisk.srl
Normal file
BIN
arm9/binaries/udisk.srl
Normal file
Binary file not shown.
5
arm9/gfx/consolebg.grit
Normal file
5
arm9/gfx/consolebg.grit
Normal file
@ -0,0 +1,5 @@
|
||||
# 8 bit bitmap
|
||||
-gB8
|
||||
|
||||
# bitmap format
|
||||
-gb
|
BIN
arm9/gfx/consolebg.png
Normal file
BIN
arm9/gfx/consolebg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
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: 734 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: 41 KiB |
225
arm9/source/args.cpp
Normal file
225
arm9/source/args.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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 SRL_EXT = ".srl";
|
||||
static const string DSI_EXT = ".dsi";
|
||||
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)return false; // Path was too long, abort
|
||||
// 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) || strCaseEnd(filePath, SRL_EXT) || strCaseEnd(filePath, DSI_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) || strCaseEnd(filePath, SRL_EXT) || strCaseEnd(filePath, DSI_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) || strCaseEnd(argarray[0], SRL_EXT) || strCaseEnd(argarray[0], DSI_EXT));
|
||||
}
|
||||
|
||||
vector<string> argsGetExtensionList() {
|
||||
vector<string> extensionList;
|
||||
// Always supported files: NDS binaries and predefined argument lists
|
||||
extensionList.push_back(NDS_EXT);
|
||||
extensionList.push_back(SRL_EXT);
|
||||
extensionList.push_back(DSI_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;
|
||||
}
|
||||
|
48
arm9/source/args.h
Normal file
48
arm9/source/args.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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
|
||||
|
17
arm9/source/binaries.h
Normal file
17
arm9/source/binaries.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef BINARIES_H
|
||||
#define BINARIES_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void udiskData();
|
||||
extern void udiskData_end();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
8
arm9/source/binaries.s
Normal file
8
arm9/source/binaries.s
Normal file
@ -0,0 +1,8 @@
|
||||
.arm
|
||||
.global udiskData, udiskData_end
|
||||
|
||||
udiskData:
|
||||
.incbin "../binaries/udisk.srl"
|
||||
udiskData_end:
|
||||
|
||||
|
177
arm9/source/file_browse.cpp
Normal file
177
arm9/source/file_browse.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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 32
|
||||
#define ENTRIES_PER_SCREEN 22
|
||||
#define ENTRIES_START_ROW 2
|
||||
#define ENTRY_PAGE_LENGTH 10
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct DirEntry { string name; bool isDirectory; };
|
||||
|
||||
bool nameEndsWith (const string& name, const vector<string> extensionList) {
|
||||
if (name.size() == 0) return false;
|
||||
if (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
|
220
arm9/source/iconTitle.cpp
Normal file
220
arm9/source/iconTitle.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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 (8*8) // 16
|
||||
#define TITLE_POS_Y (16*8) // 136
|
||||
|
||||
#define ICON_POS_X 109
|
||||
#define ICON_POS_Y 80
|
||||
|
||||
// #define TEXT_WIDTH ((32-4)*8/6) // 37.333?
|
||||
#define TEXT_WIDTH 26
|
||||
|
||||
static int bg2, bg3;
|
||||
static u16 *sprite;
|
||||
static tNDSBanner banner;
|
||||
|
||||
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
|
||||
vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_SPRITE, VRAM_C_LCD, VRAM_D_LCD);
|
||||
|
||||
// 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);
|
||||
BG_PALETTE[0xF] = RGB15(31,31,31);
|
||||
|
||||
// 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);
|
||||
|
||||
// everything's ready :)
|
||||
writeRow (1,"==>> XuluMenu <<==");
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
} else {
|
||||
std::string ndsPath;
|
||||
if (!argsNdsPath(name, ndsPath)) {
|
||||
writeRow(2, "(invalid argv or NDS file!)");
|
||||
clearIcon();
|
||||
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();
|
||||
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();
|
||||
fclose (fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Icon_title_offset == 0) {
|
||||
// text
|
||||
writeRow (2, "(no title/icon)");
|
||||
// icon
|
||||
clearIcon();
|
||||
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();
|
||||
fclose (fp);
|
||||
return;
|
||||
}
|
||||
|
||||
// close file!
|
||||
fclose (fp);
|
||||
|
||||
// turn unicode into ascii (kind of)
|
||||
// and convert 0x0A into 0x00
|
||||
char *p = (char*)banner.titles[0];
|
||||
for (size_t i = 0; i < sizeof(banner.titles[0]); i = i+2) {
|
||||
if ((p[i] == 0x0A) || (p[i] == 0xFF))
|
||||
p[i/2] = 0;
|
||||
else
|
||||
p[i/2] = p[i];
|
||||
}
|
||||
|
||||
// text
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
writeRow(i+1, 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);
|
114
arm9/source/main.cpp
Normal file
114
arm9/source/main.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Copyright (C) 2005 - 2013
|
||||
Michael "Chishm" Chisholm
|
||||
Dave "WinterMute" Murphy
|
||||
Claudio "sverx"
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
------------------------------------------------------------------*/
|
||||
#include <nds.h>
|
||||
#include <stdio.h>
|
||||
#include <fat.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "args.h"
|
||||
#include "file_browse.h"
|
||||
#include "hbmenu_banner.h"
|
||||
#include "font.h"
|
||||
#include "consolebg.h"
|
||||
#include "iconTitle.h"
|
||||
#include "nds_loader_arm9.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void InitGUI (void) {
|
||||
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(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(consolebgPal, BG_PALETTE_SUB, 256*2);
|
||||
BG_PALETTE_SUB[255] = RGB15(31,31,31);
|
||||
keysSetRepeat(25,5);
|
||||
}
|
||||
|
||||
int FileBrowser() {
|
||||
InitGUI();
|
||||
vector<string> extensionList = argsGetExtensionList();
|
||||
while(1) {
|
||||
string filename = browseForFile(extensionList);
|
||||
// Construct a command line
|
||||
vector<string> argarray;
|
||||
if (!argsFillArray(filename, argarray)) {
|
||||
iprintf("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();
|
||||
while (1) {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
if (!(keysHeld() & KEY_A)) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int RecoveryPrompt(void) {
|
||||
InitGUI();
|
||||
printf("<--------RECOVERY MODE--------->\n");
|
||||
printf("\n\nPress [A] to use built in uDisk.\n\n");
|
||||
printf("Hold [Start] + [Select] while\nbooting uDisk to enter format\nmenu.\n");
|
||||
while(1) {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
if(keysDown() & KEY_A)break;
|
||||
}
|
||||
return runUdisk();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// Any error results in starting integrated uDisk 1.45 SRL as fall back
|
||||
scanKeys();
|
||||
if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R))return RecoveryPrompt(); // Recovery option if FAT init hangs
|
||||
|
||||
if (!fatInitDefault())return RecoveryPrompt();
|
||||
if((access("/boot.nds", F_OK) == 0) && !(keysHeld() & KEY_B))runNdsFile("/boot.nds", 0, NULL);
|
||||
if((access("/udisk.nds", F_OK) == 0) && !(keysHeld() & KEY_B))runNdsFile("/udisk.nds", 0, NULL);
|
||||
FileBrowser();
|
||||
return RecoveryPrompt();
|
||||
}
|
||||
|
385
arm9/source/nds_loader_arm9.c
Normal file
385
arm9/source/nds_loader_arm9.c
Normal file
@ -0,0 +1,385 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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"
|
||||
#include "loadAlt_bin.h"
|
||||
#include "binaries.h"
|
||||
#include "tonccpy.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 vramset (volatile void* dst, u16 val, int len) {
|
||||
vu32* dst32 = (vu32*)dst;
|
||||
u32 val32 = val | (val << 16);
|
||||
for ( ; len > 0; len -= 4) { *dst32++ = val32; }
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int runUdisk() {
|
||||
tonccpy((void*)TMP_DATA, (void*)udiskData, (udiskData_end - udiskData));
|
||||
// Start Bootloader
|
||||
irqDisable(IRQ_ALL);
|
||||
// Direct CPU access to VRAM bank D
|
||||
VRAM_D_CR = VRAM_ENABLE | VRAM_D_LCD;
|
||||
// Clear VRAM
|
||||
vramset (LCDC_BANK_D, 0x0000, 128 * 1024);
|
||||
// Load the loader/patcher into the correct address
|
||||
vramcpy (LCDC_BANK_D, loadAlt_bin, loadAlt_bin_size);
|
||||
// Give the VRAM to the ARM7
|
||||
VRAM_D_CR = VRAM_ENABLE | VRAM_D_ARM7_0x06020000;
|
||||
// Reset into a passme loop
|
||||
REG_EXMEMCNT = 0xFFFF;
|
||||
*((vu32*)0x027FFFFC) = 0;
|
||||
*((vu32*)0x027FFE04) = (u32)0xE59FF018;
|
||||
*((vu32*)0x027FFE24) = (u32)0x027FFE04;
|
||||
resetARM7(0x06020000);
|
||||
swiSoftReset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
51
arm9/source/nds_loader_arm9.h
Normal file
51
arm9/source/nds_loader_arm9.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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
|
||||
|
||||
int runUdisk();
|
||||
|
||||
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
|
126
arm9/source/tonccpy.c
Normal file
126
arm9/source/tonccpy.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include <stddef.h>
|
||||
#include "tonccpy.h"
|
||||
//# tonccpy.c
|
||||
|
||||
//! VRAM-safe cpy.
|
||||
/*! This version mimics memcpy in functionality, with
|
||||
the benefit of working for VRAM as well. It is also
|
||||
slightly faster than the original memcpy, but faster
|
||||
implementations can be made.
|
||||
\param dst Destination pointer.
|
||||
\param src Source pointer.
|
||||
\param size Fill-length in bytes.
|
||||
\note The pointers and size need not be word-aligned.
|
||||
*/
|
||||
void tonccpy(void *dst, const void *src, uint size) {
|
||||
|
||||
if(size==0 || dst==NULL || src==NULL) { return; }
|
||||
|
||||
uint count;
|
||||
u16 *dst16; // hword destination
|
||||
u8 *src8; // byte source
|
||||
|
||||
// Ideal case: copy by 4x words. Leaves tail for later.
|
||||
if( ((u32)src|(u32)dst)%4==0 && size>=4) {
|
||||
u32 *src32= (u32*)src, *dst32= (u32*)dst;
|
||||
|
||||
count= size/4;
|
||||
uint tmp= count&3;
|
||||
count /= 4;
|
||||
|
||||
// Duff's Device, good friend!
|
||||
// Added fall through attribute to silance the compiler about this. ;)
|
||||
switch(tmp) {
|
||||
do { *dst32++ = *src32++; // fallthrough
|
||||
case 3: *dst32++ = *src32++; // fallthrough
|
||||
case 2: *dst32++ = *src32++; // fallthrough
|
||||
case 1: *dst32++ = *src32++; // fallthrough
|
||||
case 0: ;} while(count--); // fallthrough
|
||||
}
|
||||
|
||||
// Check for tail
|
||||
size &= 3;
|
||||
if(size == 0) { return; }
|
||||
src8= (u8*)src32;
|
||||
dst16= (u16*)dst32;
|
||||
} else {
|
||||
// Unaligned.
|
||||
uint dstOfs= (u32)dst&1;
|
||||
src8= (u8*)src;
|
||||
dst16= (u16*)(dst-dstOfs);
|
||||
|
||||
// Head: 1 byte.
|
||||
if(dstOfs != 0) {
|
||||
*dst16= (*dst16 & 0xFF) | *src8++<<8;
|
||||
dst16++;
|
||||
if(--size==0) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
// Unaligned main: copy by 2x byte.
|
||||
count= size/2;
|
||||
while(count--) {
|
||||
*dst16++ = src8[0] | src8[1]<<8;
|
||||
src8 += 2;
|
||||
}
|
||||
|
||||
// Tail: 1 byte.
|
||||
if(size&1) { *dst16= (*dst16 &~ 0xFF) | *src8; }
|
||||
}
|
||||
//# toncset.c
|
||||
|
||||
//! VRAM-safe memset, internal routine.
|
||||
/*! This version mimics memset in functionality, with
|
||||
the benefit of working for VRAM as well. It is also
|
||||
slightly faster than the original memset.
|
||||
\param dst Destination pointer.
|
||||
\param fill Word to fill with.
|
||||
\param size Fill-length in bytes.
|
||||
\note The \a dst pointer and \a size need not be
|
||||
word-aligned. In the case of unaligned fills, \a fill
|
||||
will be masked off to match the situation.
|
||||
*/
|
||||
void __toncset(void *dst, u32 fill, uint size) {
|
||||
if(size==0 || dst==NULL) { return; }
|
||||
|
||||
uint left= (u32)dst&3;
|
||||
u32 *dst32= (u32*)(dst-left);
|
||||
u32 count, mask;
|
||||
|
||||
// Unaligned head.
|
||||
if(left != 0) {
|
||||
// Adjust for very small stint.
|
||||
if(left+size<4) {
|
||||
mask= BIT_MASK(size*8)<<(left*8);
|
||||
*dst32= (*dst32 &~ mask) | (fill & mask);
|
||||
return;
|
||||
}
|
||||
|
||||
mask= BIT_MASK(left*8);
|
||||
*dst32= (*dst32 & mask) | (fill&~mask);
|
||||
dst32++;
|
||||
size -= 4-left;
|
||||
}
|
||||
|
||||
// Main stint.
|
||||
count= size/4;
|
||||
uint tmp= count&3;
|
||||
count /= 4;
|
||||
|
||||
// Added fall through attribute to silance the compiler about this. ;)
|
||||
switch(tmp) {
|
||||
do { *dst32++ = fill; // fallthrough
|
||||
case 3: *dst32++ = fill; // fallthrough
|
||||
case 2: *dst32++ = fill; // fallthrough
|
||||
case 1: *dst32++ = fill; // fallthrough
|
||||
case 0: ;} while(count--); // fallthrough
|
||||
}
|
||||
|
||||
// Tail
|
||||
size &= 3;
|
||||
if(size) {
|
||||
mask= BIT_MASK(size*8);
|
||||
*dst32= (*dst32 &~ mask) | (fill & mask);
|
||||
}
|
||||
}
|
||||
|
43
arm9/source/tonccpy.h
Normal file
43
arm9/source/tonccpy.h
Normal file
@ -0,0 +1,43 @@
|
||||
//# Stuff you may not have yet.
|
||||
|
||||
#ifndef TONCCPY_H
|
||||
#define TONCCPY_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
typedef unsigned int uint;
|
||||
#define BIT_MASK(len) ( (1<<(len))-1 )
|
||||
static inline u32 quad8(u16 x) { x |= x<<8; return x | x<<16; }
|
||||
|
||||
|
||||
//# Declarations and inlines.
|
||||
|
||||
void tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void __toncset(void *dst, u32 fill, uint size);
|
||||
static inline void toncset(void *dst, u8 src, uint size);
|
||||
static inline void toncset16(void *dst, u16 src, uint size);
|
||||
static inline void toncset32(void *dst, u32 src, uint size);
|
||||
|
||||
|
||||
//! VRAM-safe memset, byte version. Size in bytes.
|
||||
static inline void toncset(void *dst, u8 src, uint size)
|
||||
{ __toncset(dst, quad8(src), size); }
|
||||
|
||||
//! VRAM-safe memset, halfword version. Size in hwords.
|
||||
static inline void toncset16(void *dst, u16 src, uint size)
|
||||
{ __toncset(dst, src|src<<16, size*2); }
|
||||
|
||||
//! VRAM-safe memset, word version. Size in words.
|
||||
static inline void toncset32(void *dst, u32 src, uint size)
|
||||
{ __toncset(dst, src, size*4); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
3
bootloader/.gitignore
vendored
Normal file
3
bootloader/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*build
|
||||
load.bin
|
||||
load.elf
|
123
bootloader/Makefile
Normal file
123
bootloader/Makefile
Normal file
@ -0,0 +1,123 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
|
||||
endif
|
||||
|
||||
-include $(DEVKITARM)/ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := load
|
||||
BUILD ?= build
|
||||
SOURCES := source source/patches
|
||||
INCLUDES := build
|
||||
SPECS := specs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -Os -DNO_SDMMC\
|
||||
-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
bootloader/arm9code/mpu_reset.s
Normal file
110
bootloader/arm9code/mpu_reset.s
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright 2006 - 2015 Dave Murphy (WinterMute)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <nds/arm9/cache_asm.h>
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.arm
|
||||
|
||||
.arch armv5te
|
||||
.cpu arm946e-s
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
.global _start
|
||||
.type _start STT_FUNC
|
||||
@---------------------------------------------------------------------------------
|
||||
_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Switch off MPU
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, r0, #PROTECT_ENABLE
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
|
||||
adr r12, mpu_initial_data
|
||||
ldmia r12, {r0-r10}
|
||||
|
||||
mcr p15, 0, r0, c2, c0, 0
|
||||
mcr p15, 0, r0, c2, c0, 1
|
||||
mcr p15, 0, r1, c3, c0, 0
|
||||
mcr p15, 0, r2, c5, c0, 2
|
||||
mcr p15, 0, r3, c5, c0, 3
|
||||
mcr p15, 0, r4, c6, c0, 0
|
||||
mcr p15, 0, r5, c6, c1, 0
|
||||
mcr p15, 0, r6, c6, c3, 0
|
||||
mcr p15, 0, r7, c6, c4, 0
|
||||
mcr p15, 0, r8, c6, c6, 0
|
||||
mcr p15, 0, r9, c6, c7, 0
|
||||
mcr p15, 0, r10, c9, c1, 0
|
||||
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c6, c2, 0 @ PU Protection Unit Data/Unified Region 2
|
||||
mcr p15, 0, r0, c6, c5, 0 @ PU Protection Unit Data/Unified Region 5
|
||||
|
||||
mrc p15, 0, r0, c9, c1, 0 @ DTCM
|
||||
mov r0, r0, lsr #12 @ base
|
||||
mov r0, r0, lsl #12 @ size
|
||||
add r0, r0, #0x4000 @ dtcm top
|
||||
|
||||
sub r0, r0, #4 @ irq vector
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
sub r0, r0, #4 @ IRQ1 Check Bits
|
||||
str r1, [r0]
|
||||
|
||||
sub r0, r0, #128
|
||||
bic r0, r0, #7
|
||||
|
||||
msr cpsr_c, #0xd3 @ svc mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #128
|
||||
msr cpsr_c, #0xd2 @ irq mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #128
|
||||
msr cpsr_c, #0xdf @ system mode
|
||||
mov sp, r0
|
||||
|
||||
@ enable cache & tcm
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
ldr r1,= ITCM_ENABLE | DTCM_ENABLE | ICACHE_ENABLE | DCACHE_ENABLE
|
||||
orr r0,r0,r1
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
ldr r10, =0x2FFFE04
|
||||
ldr r0, =0xE59FF018
|
||||
str r0, [r10]
|
||||
add r1, r10, #0x20
|
||||
str r10, [r1]
|
||||
bx r10
|
||||
|
||||
.pool
|
||||
|
||||
mpu_initial_data:
|
||||
.word 0x00000042 @ p15,0,c2,c0,0..1,r0 ;PU Cachability Bits for Data/Unified+Instruction Protection Region
|
||||
.word 0x00000002 @ p15,0,c3,c0,0,r1 ;PU Write-Bufferability Bits for Data Protection Regions
|
||||
.word 0x15111011 @ p15,0,c5,c0,2,r2 ;PU Extended Access Permission Data/Unified Protection Region
|
||||
.word 0x05100011 @ p15,0,c5,c0,3,r3 ;PU Extended Access Permission Instruction Protection Region
|
||||
.word 0x04000033 @ p15,0,c6,c0,0,r4 ;PU Protection Unit Data/Unified Region 0
|
||||
.word 0x0200002b @ p15,0,c6,c1,0,r5 ;PU Protection Unit Data/Unified Region 1 4MB
|
||||
.word 0x08000035 @ p15,0,c6,c3,0,r6 ;PU Protection Unit Data/Unified Region 3
|
||||
.word 0x0300001b @ p15,0,c6,c4,0,r7 ;PU Protection Unit Data/Unified Region 4
|
||||
.word 0xffff001d @ p15,0,c6,c6,0,r8 ;PU Protection Unit Data/Unified Region 6
|
||||
.word 0x02fff017 @ p15,0,c6,c7,0,r9 ;PU Protection Unit Data/Unified Region 7 4KB
|
||||
.word 0x0300000a @ p15,0,c9,c1,0,r10 ;TCM Data TCM Base and Virtual Size
|
198
bootloader/load.ld
Normal file
198
bootloader/load.ld
Normal file
@ -0,0 +1,198 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY {
|
||||
|
||||
vram : ORIGIN = 0x06020000, LENGTH = 128K
|
||||
}
|
||||
|
||||
__vram_start = ORIGIN(vram);
|
||||
__vram_top = ORIGIN(vram)+ LENGTH(vram);
|
||||
__sp_irq = __vram_top - 0x60;
|
||||
__sp_svc = __sp_irq - 0x100;
|
||||
__sp_usr = __sp_svc - 0x100;
|
||||
|
||||
__irq_flags = __vram_top - 8;
|
||||
__irq_vector = __vram_top - 4;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
__text_start = . ;
|
||||
KEEP (*(.init))
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
} >vram = 0xff
|
||||
|
||||
.text : /* ALIGN (4): */
|
||||
{
|
||||
|
||||
*(.text*)
|
||||
*(.stub)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} >vram =0xff
|
||||
|
||||
__text_end = . ;
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata)
|
||||
*all.rodata*(*)
|
||||
*(.roda)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r*)
|
||||
SORT(CONSTRUCTORS)
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >vram
|
||||
__exidx_start = .;
|
||||
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >vram
|
||||
__exidx_end = .;
|
||||
|
||||
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||
could instead move the label definition inside the section, but
|
||||
the linker would then create the section even if it turns out to
|
||||
be empty, which isn't pretty. */
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { KEEP (*(.preinit_array)) } >vram = 0xff
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { KEEP (*(.init_array)) } >vram = 0xff
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { KEEP (*(.fini_array)) } >vram = 0xff
|
||||
PROVIDE (__fini_array_end = .);
|
||||
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of the constructors, so
|
||||
we make sure it is first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not actually link against
|
||||
crtbegin.o; the linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it doesn't matter which
|
||||
directory crtbegin.o is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.eh_frame :
|
||||
{
|
||||
KEEP (*(.eh_frame))
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.gcc_except_table :
|
||||
{
|
||||
*(.gcc_except_table)
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
.jcr : { KEEP (*(.jcr)) } >vram = 0
|
||||
.got : { *(.got.plt) *(.got) } >vram = 0
|
||||
|
||||
|
||||
.vram ALIGN(4) :
|
||||
{
|
||||
__vram_start = ABSOLUTE(.) ;
|
||||
*(.vram)
|
||||
*vram.*(.text)
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
__vram_end = ABSOLUTE(.) ;
|
||||
} >vram = 0xff
|
||||
|
||||
|
||||
.data ALIGN(4) : {
|
||||
__data_start = ABSOLUTE(.);
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
. = ALIGN(4);
|
||||
__data_end = ABSOLUTE(.) ;
|
||||
} >vram = 0xff
|
||||
|
||||
|
||||
|
||||
.bss ALIGN(4) :
|
||||
{
|
||||
__bss_start = ABSOLUTE(.);
|
||||
__bss_start__ = ABSOLUTE(.);
|
||||
*(.dynbss)
|
||||
*(.gnu.linkonce.b*)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram
|
||||
|
||||
__bss_end = . ;
|
||||
__bss_end__ = . ;
|
||||
|
||||
_end = . ;
|
||||
__end__ = . ;
|
||||
PROVIDE (end = _end);
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.stack 0x80000 : { _stack = .; *(.stack) }
|
||||
/* These must appear regardless of . */
|
||||
}
|
70
bootloader/source/arm7clear.s
Normal file
70
bootloader/source/arm7clear.s
Normal file
@ -0,0 +1,70 @@
|
||||
/*-----------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
If you use this code, please give due credit and email me about your
|
||||
project at chishm@hotmail.com
|
||||
------------------------------------------------------------------*/
|
||||
|
||||
.arm
|
||||
.global arm7clearRAM
|
||||
.type arm7clearRAM STT_FUNC
|
||||
arm7clearRAM:
|
||||
|
||||
push {r0-r9}
|
||||
// clear exclusive IWRAM
|
||||
// 0380:0000 to 0380:FFFF, total 64KiB
|
||||
mov r0, #0
|
||||
mov r1, #0
|
||||
mov r2, #0
|
||||
mov r3, #0
|
||||
mov r4, #0
|
||||
mov r5, #0
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
mov r8, #0x03800000
|
||||
sub r8, #0x00008000
|
||||
mov r9, #0x03800000
|
||||
orr r9, r9, #0x10000
|
||||
clear_IWRAM_loop:
|
||||
stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7}
|
||||
cmp r8, r9
|
||||
blt clear_IWRAM_loop
|
||||
|
||||
// clear most of EWRAM - except after RAM end - 0xc000, which has the bootstub
|
||||
mov r8, #0x02000000
|
||||
|
||||
ldr r9,=0x4004008
|
||||
ldr r9,[r9]
|
||||
ands r9,r9,#0x8000
|
||||
bne dsi_mode
|
||||
|
||||
mov r9, #0x02400000
|
||||
b ds_mode
|
||||
dsi_mode:
|
||||
mov r9, #0x03000000
|
||||
ds_mode:
|
||||
sub r9, #0x0000c000
|
||||
clear_EWRAM_loop:
|
||||
stmia r8!, {r0, r1, r2, r3, r4, r5, r6, r7}
|
||||
cmp r8, r9
|
||||
blt clear_EWRAM_loop
|
||||
|
||||
pop {r0-r9}
|
||||
|
||||
bx lr
|
||||
|
72
bootloader/source/arm9clear.arm.c
Normal file
72
bootloader/source/arm9clear.arm.c
Normal file
@ -0,0 +1,72 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
// Removed VRAM/Screen clearing code to speed up transition. Things seem to boot fine without it.
|
||||
|
||||
//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
bootloader/source/arm9mpu_reset.s
Normal file
6
bootloader/source/arm9mpu_reset.s
Normal file
@ -0,0 +1,6 @@
|
||||
.arm
|
||||
.global mpu_reset, mpu_reset_end
|
||||
|
||||
mpu_reset:
|
||||
.incbin "mpu_reset.bin"
|
||||
mpu_reset_end:
|
13
bootloader/source/bios.s
Normal file
13
bootloader/source/bios.s
Normal file
@ -0,0 +1,13 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.thumb
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
.global swiDelay
|
||||
.thumb_func
|
||||
@---------------------------------------------------------------------------------
|
||||
swiDelay:
|
||||
@---------------------------------------------------------------------------------
|
||||
swi 0x03
|
||||
bx lr
|
387
bootloader/source/boot.c
Normal file
387
bootloader/source/boot.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*-----------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
if ((fileCluster < CLUSTER_FIRST) || (fileCluster >= CLUSTER_EOF)) /* Invalid file cluster specified */
|
||||
{
|
||||
fileCluster = getBootFileCluster(bootName);
|
||||
}
|
||||
if (fileCluster == CLUSTER_FREE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ARM9 clears its memory part 2
|
||||
// copy ARM9 function to RAM, and make the ARM9 jump to it
|
||||
copyLoop((void*)TEMP_MEM, (void*)resetMemory2_ARM9, resetMemory2_ARM9_size);
|
||||
(*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function
|
||||
// Wait until the ARM9 has completed its task
|
||||
while ((*(vu32*)0x02FFFE24) == (u32)TEMP_MEM);
|
||||
|
||||
// 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
bootloader/source/boot.h
Normal file
10
bootloader/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_
|
46
bootloader/source/card.h
Normal file
46
bootloader/source/card.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*-----------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
If you use this code, please give due credit and email me about your
|
||||
project at chishm@hotmail.com
|
||||
------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CARD_H
|
||||
#define CARD_H
|
||||
|
||||
#include "disc_io.h"
|
||||
#include "io_dldi.h"
|
||||
|
||||
static inline bool CARD_StartUp (void) {
|
||||
return _io_dldi.fn_startup();
|
||||
}
|
||||
|
||||
static inline bool CARD_IsInserted (void) {
|
||||
return _io_dldi.fn_isInserted();
|
||||
}
|
||||
|
||||
static inline bool CARD_ReadSector (u32 sector, void *buffer) {
|
||||
return _io_dldi.fn_readSectors(sector, 1, buffer);
|
||||
}
|
||||
|
||||
static inline bool CARD_ReadSectors (u32 sector, int count, void *buffer) {
|
||||
return _io_dldi.fn_readSectors(sector, count, buffer);
|
||||
}
|
||||
|
||||
#endif // CARD_H
|
||||
|
82
bootloader/source/disc_io.h
Normal file
82
bootloader/source/disc_io.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
disc_io.h
|
||||
Interface template for low level disc functions.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
2006-07-11 - Chishm
|
||||
* Original release
|
||||
|
||||
2006-07-16 - Chishm
|
||||
* Renamed _CF_USE_DMA to _IO_USE_DMA
|
||||
* Renamed _CF_ALLOW_UNALIGNED to _IO_ALLOW_UNALIGNED
|
||||
*/
|
||||
|
||||
#ifndef _DISC_IO_H
|
||||
#define _DISC_IO_H
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
#define BYTES_PER_SECTOR 512
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Customisable features
|
||||
|
||||
// Use DMA to read the card, remove this line to use normal reads/writes
|
||||
// #define _IO_USE_DMA
|
||||
|
||||
// Allow buffers not alligned to 16 bits when reading files.
|
||||
// Note that this will slow down access speed, so only use if you have to.
|
||||
// It is also incompatible with DMA
|
||||
#define _IO_ALLOW_UNALIGNED
|
||||
|
||||
#if defined _IO_USE_DMA && defined _IO_ALLOW_UNALIGNED
|
||||
#error "You can't use both DMA and unaligned memory"
|
||||
#endif
|
||||
|
||||
#define FEATURE_MEDIUM_CANREAD 0x00000001
|
||||
#define FEATURE_MEDIUM_CANWRITE 0x00000002
|
||||
#define FEATURE_SLOT_GBA 0x00000010
|
||||
#define FEATURE_SLOT_NDS 0x00000020
|
||||
|
||||
typedef bool (* FN_MEDIUM_STARTUP)(void) ;
|
||||
typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
|
||||
typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u32 numSectors, void* buffer) ;
|
||||
typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u32 numSectors, const void* buffer) ;
|
||||
typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
|
||||
typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
|
||||
|
||||
struct IO_INTERFACE_STRUCT {
|
||||
unsigned long ioType ;
|
||||
unsigned long features ;
|
||||
FN_MEDIUM_STARTUP fn_startup ;
|
||||
FN_MEDIUM_ISINSERTED fn_isInserted ;
|
||||
FN_MEDIUM_READSECTORS fn_readSectors ;
|
||||
FN_MEDIUM_WRITESECTORS fn_writeSectors ;
|
||||
FN_MEDIUM_CLEARSTATUS fn_clearStatus ;
|
||||
FN_MEDIUM_SHUTDOWN fn_shutdown ;
|
||||
} ;
|
||||
|
||||
typedef struct IO_INTERFACE_STRUCT IO_INTERFACE ;
|
||||
|
||||
#endif // define _DISC_IO_H
|
223
bootloader/source/dldi_patcher.c
Normal file
223
bootloader/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
bootloader/source/dldi_patcher.h
Normal file
32
bootloader/source/dldi_patcher.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*-----------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
If you use this code, please give due credit and email me about your
|
||||
project at chishm@hotmail.com
|
||||
------------------------------------------------------------------*/
|
||||
|
||||
#ifndef DLDI_PATCHER_H
|
||||
#define DLDI_PATCHER_H
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
typedef signed int addr_t;
|
||||
typedef unsigned char data_t;
|
||||
bool dldiPatchBinary (data_t *binData, u32 binSize);
|
||||
|
||||
#endif // DLDI_PATCHER_H
|
592
bootloader/source/fat.c
Normal file
592
bootloader/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
bootloader/source/fat.h
Normal file
46
bootloader/source/fat.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*-----------------------------------------------------------------
|
||||
fat.h
|
||||
|
||||
NDS MP
|
||||
GBAMP NDS Firmware Hack Version 2.12
|
||||
An NDS aware firmware patch for the GBA Movie Player.
|
||||
By Michael Chisholm (Chishm)
|
||||
|
||||
Filesystem code based on GBAMP_CF.c by Chishm (me).
|
||||
|
||||
License:
|
||||
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
If you use this code, please give due credit and email me about your
|
||||
project at chishm@hotmail.com
|
||||
------------------------------------------------------------------*/
|
||||
|
||||
#ifndef FAT_H
|
||||
#define FAT_H
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
#define CLUSTER_FREE 0x00000000
|
||||
#define CLUSTER_EOF 0x0FFFFFFF
|
||||
#define CLUSTER_FIRST 0x00000002
|
||||
|
||||
bool FAT_InitFiles (bool initCard);
|
||||
u32 getBootFileCluster (const char* bootName);
|
||||
u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length);
|
||||
u32 FAT_ClustToSect (u32 cluster);
|
||||
|
||||
#endif // FAT_H
|
44
bootloader/source/io_dldi.h
Normal file
44
bootloader/source/io_dldi.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
io_dldi.h
|
||||
|
||||
Reserved space for post-compilation adding of an extra driver
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
2006-12-22 - Chishm
|
||||
* Original release
|
||||
*/
|
||||
|
||||
#ifndef IO_DLDI_H
|
||||
#define IO_DLDI_H
|
||||
|
||||
// 'DLDD'
|
||||
#define DEVICE_TYPE_DLDD 0x49444C44
|
||||
|
||||
#include "disc_io.h"
|
||||
|
||||
// export interface
|
||||
extern IO_INTERFACE _io_dldi ;
|
||||
|
||||
#endif // define IO_DLDI_H
|
124
bootloader/source/io_dldi.s
Normal file
124
bootloader/source/io_dldi.s
Normal file
@ -0,0 +1,124 @@
|
||||
/*-----------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
If you use this code, please give due credit and email me about your
|
||||
project at chishm@hotmail.com
|
||||
------------------------------------------------------------------*/
|
||||
@---------------------------------------------------------------------------------
|
||||
.align 4
|
||||
.arm
|
||||
.global _dldi_start
|
||||
.global _io_dldi
|
||||
@---------------------------------------------------------------------------------
|
||||
.equ FEATURE_MEDIUM_CANREAD, 0x00000001
|
||||
.equ FEATURE_MEDIUM_CANWRITE, 0x00000002
|
||||
.equ FEATURE_SLOT_GBA, 0x00000010
|
||||
.equ FEATURE_SLOT_NDS, 0x00000020
|
||||
|
||||
|
||||
_dldi_start:
|
||||
#ifndef NO_DLDI
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Driver patch file standard header -- 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
bootloader/source/load_crt0.s
Normal file
147
bootloader/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
bootloader/source/sdmmc.c
Normal file
242
bootloader/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
bootloader/source/sdmmc.h
Normal file
194
bootloader/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
|
3
bootloaderalt/.gitignore
vendored
Normal file
3
bootloaderalt/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*build
|
||||
loadAlt.bin
|
||||
loadAlt.elf
|
126
bootloaderalt/Makefile
Normal file
126
bootloaderalt/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
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := loadAlt
|
||||
BUILD := build
|
||||
SOURCES := source source/patches
|
||||
INCLUDES := build ../include
|
||||
DATA := ../data
|
||||
SPECS := specs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb-interwork -march=armv4t -mtune=arm7tdmi
|
||||
|
||||
CFLAGS := -g -Wall -O2\
|
||||
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||
-fomit-frame-pointer\
|
||||
-ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM7 -std=gnu99
|
||||
|
||||
ASFLAGS := -g $(ARCH) $(INCLUDE)
|
||||
LDFLAGS = -nostartfiles -T $(TOPDIR)/load.ld -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(TARGET).map
|
||||
|
||||
LIBS := -lnds7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export TOPDIR := $(CURDIR)
|
||||
export LOADBIN := $(CURDIR)/../data/$(TARGET).bin
|
||||
export LOADELF := $(CURDIR)/$(TARGET).elf
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AR := $(PREFIX)ar
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
|
||||
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CC for linking standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) *.elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
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 $@
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
226
bootloaderalt/load.ld
Normal file
226
bootloaderalt/load.ld
Normal file
@ -0,0 +1,226 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY {
|
||||
|
||||
vram : ORIGIN = 0x06020000, LENGTH = 64K
|
||||
arm9ram : ORIGIN = 0x027FD800, LENGTH = 4K
|
||||
}
|
||||
|
||||
__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;
|
||||
|
||||
|
||||
__arm9ram_start = ORIGIN(arm9ram);
|
||||
__arm9ram_top = ORIGIN(arm9ram)+ LENGTH(arm9ram);
|
||||
|
||||
/* No IRQs or SVC calls in ARM9 boot code so give them minimal stacks */
|
||||
__arm9_sp_irq = __arm9ram_top;
|
||||
__arm9_sp_svc = __arm9_sp_irq - 0x10;
|
||||
__arm9_sp_usr = __arm9_sp_svc - 0x10;
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
__text_start = . ;
|
||||
KEEP (*(.init))
|
||||
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||
} >vram = 0xff
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
} >vram = 0xff
|
||||
|
||||
__arm9_source_start = . ;
|
||||
.arm9 :
|
||||
{
|
||||
__arm9_start = . ;
|
||||
*.arm9.*(.text*)
|
||||
*.arm9.*(.data*)
|
||||
__arm9_bss_start = ABSOLUTE(.);
|
||||
*.arm9.*(.bss*)
|
||||
__arm9_bss_end = ABSOLUTE(.);
|
||||
__arm9_end = . ;
|
||||
} >arm9ram AT>vram =0xff
|
||||
__arm9_source_end = __arm9_source_start + SIZEOF(.arm9);
|
||||
|
||||
. = __arm9_source_end;
|
||||
. = ALIGN(4);
|
||||
|
||||
.text ALIGN(4) : /* ALIGN (4): */
|
||||
{
|
||||
*(.text)
|
||||
*(.stub)
|
||||
*(.text.*)
|
||||
/* .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 . */
|
||||
}
|
45
bootloaderalt/source/clear_cache.arm9.s
Normal file
45
bootloaderalt/source/clear_cache.arm9.s
Normal file
@ -0,0 +1,45 @@
|
||||
@ NitroHax -- Cheat tool for the Nintendo DS
|
||||
@ Copyright (C) 2008 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 3 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/>.
|
||||
|
||||
@ Clears ICache and Dcache, and resets the protection units
|
||||
@ Originally written by Darkain, modified by Chishm
|
||||
|
||||
#include <nds/asminc.h>
|
||||
|
||||
.arm
|
||||
|
||||
BEGIN_ASM_FUNC arm9_clearCache
|
||||
@ Clean and flush cache
|
||||
mov r1, #0
|
||||
outer_loop:
|
||||
mov r0, #0
|
||||
inner_loop:
|
||||
orr r2, r1, r0
|
||||
mcr p15, 0, r2, c7, c14, 2
|
||||
add r0, r0, #0x20
|
||||
cmp r0, #0x400
|
||||
bne inner_loop
|
||||
add r1, r1, #0x40000000
|
||||
cmp r1, #0x0
|
||||
bne outer_loop
|
||||
|
||||
mov r3, #0
|
||||
mcr p15, 0, r3, c7, c5, 0 @ Flush ICache
|
||||
mcr p15, 0, r3, c7, c6, 0 @ Flush DCache
|
||||
mcr p15, 0, r3, c7, c10, 4 @ empty write buffer
|
||||
|
||||
bx lr
|
||||
|
44
bootloaderalt/source/clear_mem.s
Normal file
44
bootloaderalt/source/clear_mem.s
Normal file
@ -0,0 +1,44 @@
|
||||
@ NitroHax -- Cheat tool for the Nintendo DS
|
||||
@ Copyright (C) 2008 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 3 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/>.
|
||||
|
||||
@ void arm7_clearmem (void* loc, size_t len);
|
||||
@ Clears memory using an stmia loop
|
||||
|
||||
#include <nds/asminc.h>
|
||||
|
||||
.arm
|
||||
|
||||
|
||||
BEGIN_ASM_FUNC arm7_clearmem
|
||||
add r1, r0, r1
|
||||
stmfd sp!, {r4-r9}
|
||||
mov r2, #0
|
||||
mov r3, #0
|
||||
mov r4, #0
|
||||
mov r5, #0
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
mov r8, #0
|
||||
mov r9, #0
|
||||
|
||||
clearmem_loop:
|
||||
stmia r0!, {r2-r9}
|
||||
cmp r0, r1
|
||||
blt clearmem_loop
|
||||
|
||||
ldmfd sp!, {r4-r9}
|
||||
bx lr
|
||||
|
65
bootloaderalt/source/common.h
Normal file
65
bootloaderalt/source/common.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
NitroHax -- Cheat tool for the Nintendo DS
|
||||
Copyright (C) 2008 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 3 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <nds/dma.h>
|
||||
#include <nds/ipc.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define resetCpu() \
|
||||
__asm volatile("swi 0x000000")
|
||||
|
||||
// Values fixed so they can be shared with ASM code
|
||||
enum ARM9_STATE {
|
||||
ARM9_BOOT = 0,
|
||||
ARM9_START = 1,
|
||||
ARM9_RESET = 2,
|
||||
ARM9_READY = 3,
|
||||
ARM9_MEMCLR = 4
|
||||
};
|
||||
|
||||
enum ARM7_STATE {
|
||||
ARM7_BOOT = 0,
|
||||
ARM7_START = 1,
|
||||
ARM7_RESET = 2,
|
||||
ARM7_READY = 3,
|
||||
ARM7_MEMCLR = 4,
|
||||
ARM7_LOADBIN = 5,
|
||||
ARM7_BOOTBIN = 6,
|
||||
ARM7_ERR = 7
|
||||
};
|
||||
|
||||
static inline void dmaFill(const void* src, void* dest, uint32 size) {
|
||||
DMA_SRC(3) = (uint32)src;
|
||||
DMA_DEST(3) = (uint32)dest;
|
||||
DMA_CR(3) = DMA_COPY_WORDS | DMA_SRC_FIX | (size>>2);
|
||||
while(DMA_CR(3) & DMA_BUSY);
|
||||
}
|
||||
|
||||
static inline void copyLoop (u32* dest, const u32* src, size_t size) {
|
||||
do { *dest++ = *src++; } while (size -= 4);
|
||||
}
|
||||
|
||||
static inline void ipcSendState(uint8_t state) { REG_IPC_SYNC = (state & 0x0f) << 8; }
|
||||
|
||||
static inline uint8_t ipcRecvState(void) { return (uint8_t)(REG_IPC_SYNC & 0x0f); }
|
||||
|
||||
#endif // _COMMON_H
|
||||
|
62
bootloaderalt/source/crt0.arm9.s
Normal file
62
bootloaderalt/source/crt0.arm9.s
Normal file
@ -0,0 +1,62 @@
|
||||
@---------------------------------------------------------------------------------
|
||||
.global _arm9_start
|
||||
@---------------------------------------------------------------------------------
|
||||
.align 4
|
||||
.arm
|
||||
@---------------------------------------------------------------------------------
|
||||
_arm9_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #0x04000000 @ IME = 0;
|
||||
add r0, r0, #0x208
|
||||
strh r0, [r0]
|
||||
|
||||
mov r0, #0x12 @ Switch to IRQ Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__arm9_sp_irq @ Set IRQ stack
|
||||
|
||||
mov r0, #0x13 @ Switch to SVC Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__arm9_sp_svc @ Set SVC stack
|
||||
|
||||
mov r0, #0x1F @ Switch to System Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__arm9_sp_usr @ Set user stack
|
||||
|
||||
ldr r0, =__arm9_bss_start @ Clear BSS section to 0x00
|
||||
ldr r1, =__arm9_bss_end
|
||||
sub r1, r1, r0
|
||||
bl ClearMem
|
||||
|
||||
mov r0, #0 @ int argc
|
||||
mov r1, #0 @ char *argv[]
|
||||
ldr r3, =arm9_main
|
||||
bl _blx_r3_stub @ jump to user code
|
||||
|
||||
@ If the user ever returns, restart
|
||||
b _arm9_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
|
||||
|
108
bootloaderalt/source/launch_ds_crt0.s
Normal file
108
bootloaderalt/source/launch_ds_crt0.s
Normal file
@ -0,0 +1,108 @@
|
||||
@---------------------------------------------------------------------------------
|
||||
.section ".init"
|
||||
.global _start
|
||||
@---------------------------------------------------------------------------------
|
||||
.align 4
|
||||
.arm
|
||||
@---------------------------------------------------------------------------------
|
||||
_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #0x04000000 @ IME = 0;
|
||||
add r0, r0, #0x208
|
||||
strh r0, [r0]
|
||||
|
||||
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
|
||||
|
||||
@ Load ARM9 region into main RAM
|
||||
ldr r1, =__arm9_source_start
|
||||
ldr r2, =__arm9_start
|
||||
ldr r3, =__arm9_source_end
|
||||
sub r3, r3, r1
|
||||
bl CopyMem
|
||||
|
||||
@ Start ARM9 binary
|
||||
ldr r0, =0x027FFE24
|
||||
ldr r1, =_arm9_start
|
||||
str r1, [r0]
|
||||
|
||||
mov r0, #0 @ int argc
|
||||
mov r1, #0 @ char *argv[]
|
||||
ldr r3, =arm7_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
|
||||
@---------------------------------------------------------------------------------
|
181
bootloaderalt/source/main.arm7.c
Normal file
181
bootloaderalt/source/main.arm7.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
main.arm7.c
|
||||
|
||||
By Michael Chisholm (Chishm)
|
||||
|
||||
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:
|
||||
NitroHax -- Cheat tool for the Nintendo DS
|
||||
Copyright (C) 2008 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 3 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/>.
|
||||
*/
|
||||
|
||||
#ifndef ARM7
|
||||
# define ARM7
|
||||
#endif
|
||||
#include <nds/ndstypes.h>
|
||||
#include <nds/memory.h>
|
||||
#include <nds/system.h>
|
||||
#include <nds/interrupts.h>
|
||||
#include <nds/timers.h>
|
||||
#include <nds/dma.h>
|
||||
#include <nds/arm7/audio.h>
|
||||
#include <nds/ipc.h>
|
||||
#include <nds/card.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "tonccpy.h"
|
||||
|
||||
extern void arm7_clearmem (void* loc, size_t len);
|
||||
extern void arm7_reset (void);
|
||||
|
||||
#define NDS_HEADER 0x027FFE00
|
||||
|
||||
#define TMP_DATA 0x02100000
|
||||
|
||||
#define FW_READ 0x03
|
||||
tNDSHeader* ndsHeader;
|
||||
|
||||
void arm7_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;
|
||||
}
|
||||
|
||||
void arm7_resetMemory () {
|
||||
int i;
|
||||
u8 settings1, settings2;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Clear out FIFO
|
||||
REG_IPC_SYNC = 0;
|
||||
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR;
|
||||
REG_IPC_FIFO_CR = 0;
|
||||
|
||||
// clear IWRAM - 037F:8000 to 0380:FFFF, total 96KiB
|
||||
arm7_clearmem ((void*)0x037F8000, 96*1024);
|
||||
|
||||
// clear last part of EXRAM, skipping the ARM9's section
|
||||
arm7_clearmem ((void*)0x023FE000, 0x2000);
|
||||
|
||||
// clear most of EXRAM - except after 0x023FD800, which has the ARM9 code
|
||||
// arm7_clearmem ((void*)0x02000000, 0x003FD800);
|
||||
arm7_clearmem ((void*)0x02000000, 0x000FFFFF); // Skip temperary header/binary data
|
||||
|
||||
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 stuffs
|
||||
|
||||
// Reload DS Firmware settings
|
||||
arm7_readFirmware((u32)0x03FE70, &settings1, 0x1);
|
||||
arm7_readFirmware((u32)0x03FF70, &settings2, 0x1);
|
||||
|
||||
if (settings1 > settings2) {
|
||||
arm7_readFirmware((u32)0x03FE00, (u8*)0x027FFC80, 0x70);
|
||||
arm7_readFirmware((u32)0x03FF00, (u8*)0x027FFD80, 0x70);
|
||||
} else {
|
||||
arm7_readFirmware((u32)0x03FF00, (u8*)0x027FFC80, 0x70);
|
||||
arm7_readFirmware((u32)0x03FE00, (u8*)0x027FFD80, 0x70);
|
||||
}
|
||||
|
||||
// Load FW header
|
||||
arm7_readFirmware((u32)0x000000, (u8*)0x027FF830, 0x20);
|
||||
|
||||
}
|
||||
|
||||
void arm7_loadBinary() {
|
||||
tonccpy((void*)NDS_HEADER, (void*)TMP_DATA, 0x160);
|
||||
|
||||
ndsHeader = (tNDSHeader*)NDS_HEADER;
|
||||
|
||||
// Copy arm binaries and header to intended locations.
|
||||
tonccpy((void*)ndsHeader->arm9destination, ((void*)((u32)TMP_DATA + ndsHeader->arm9romOffset)), ndsHeader->arm9binarySize);
|
||||
tonccpy((void*)ndsHeader->arm7destination, ((void*)((u32)TMP_DATA + ndsHeader->arm7romOffset)), ndsHeader->arm7binarySize);
|
||||
|
||||
// Clear temperary rom data now that they are copied
|
||||
arm7_clearmem ((void*)0x02100000, ndsHeader->romSize);
|
||||
}
|
||||
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Main function
|
||||
void arm7_main (void) {
|
||||
// Synchronise start
|
||||
while (ipcRecvState() != ARM9_START);
|
||||
ipcSendState(ARM7_START);
|
||||
|
||||
// Wait until ARM9 is ready
|
||||
while (ipcRecvState() != ARM9_READY);
|
||||
|
||||
ipcSendState(ARM7_MEMCLR);
|
||||
|
||||
// Get ARM7 to clear RAM
|
||||
arm7_resetMemory();
|
||||
|
||||
ipcSendState(ARM7_LOADBIN);
|
||||
|
||||
arm7_loadBinary();
|
||||
|
||||
ipcSendState(ARM7_BOOTBIN);
|
||||
|
||||
arm7_reset();
|
||||
}
|
||||
|
95
bootloaderalt/source/main.arm9.c
Normal file
95
bootloaderalt/source/main.arm9.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
main.arm9.c
|
||||
|
||||
By Michael Chisholm (Chishm)
|
||||
|
||||
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:
|
||||
NitroHax -- Cheat tool for the Nintendo DS
|
||||
Copyright (C) 2008 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 3 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/>.
|
||||
*/
|
||||
|
||||
#define ARM9
|
||||
#undef ARM7
|
||||
#include <nds/memory.h>
|
||||
#include <nds/arm9/video.h>
|
||||
#include <nds/arm9/input.h>
|
||||
#include <nds/interrupts.h>
|
||||
#include <nds/dma.h>
|
||||
#include <nds/timers.h>
|
||||
#include <nds/system.h>
|
||||
#include <nds/ipc.h>
|
||||
|
||||
#include "common.h"
|
||||
volatile u32 arm9_BLANK_RAM = 0;
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
External functions
|
||||
--------------------------------------------------------------------------*/
|
||||
extern void arm9_clearCache (void);
|
||||
extern void arm9_reset (void);
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
arm9_main
|
||||
Clears the ARM9's icahce and dcache
|
||||
Clears the ARM9's DMA channels and resets video memory
|
||||
Jumps to the ARM9 NDS binary in sync with the ARM7
|
||||
Written by Darkain, modified by Chishm
|
||||
--------------------------------------------------------------------------*/
|
||||
void arm9_main (void) {
|
||||
register int i;
|
||||
//set shared ram to ARM7
|
||||
WRAM_CR = 0x03;
|
||||
REG_EXMEMCNT = 0xE880;
|
||||
// Disable interrupts
|
||||
REG_IME = 0;
|
||||
REG_IE = 0;
|
||||
REG_IF = ~0;
|
||||
// Synchronise start
|
||||
ipcSendState(ARM9_START);
|
||||
while (ipcRecvState() != ARM7_START);
|
||||
ipcSendState(ARM9_MEMCLR);
|
||||
arm9_clearCache();
|
||||
for (i=0; i<16*1024; i+=4) { //first 16KB
|
||||
(*(vu32*)(i+0x00000000)) = 0x00000000; //clear ITCM
|
||||
(*(vu32*)(i+0x00800000)) = 0x00000000; //clear DTCM
|
||||
}
|
||||
for (i=16*1024; i<32*1024; i+=4) { //second 16KB
|
||||
(*(vu32*)(i+0x00000000)) = 0x00000000; //clear ITCM
|
||||
}
|
||||
(*(vu32*)0x00803FFC) = 0; //IRQ_HANDLER ARM9 version
|
||||
(*(vu32*)0x00803FF8) = ~0; //VBLANK_INTR_WAIT_FLAGS ARM9 version
|
||||
// Clear out FIFO
|
||||
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR;
|
||||
REG_IPC_FIFO_CR = 0;
|
||||
// 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 ARM9 state to ready and wait for instructions from ARM7
|
||||
ipcSendState(ARM9_READY);
|
||||
while (ipcRecvState() != ARM7_BOOTBIN);
|
||||
arm9_reset();
|
||||
}
|
||||
|
20
bootloaderalt/source/read_bios.h
Normal file
20
bootloaderalt/source/read_bios.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
NitroHax -- Cheat tool for the Nintendo DS
|
||||
Copyright (C) 2008 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 3 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/ndstypes.h>
|
||||
|
||||
void readBios (u8* dest, u32 src, u32 size);
|
54
bootloaderalt/source/read_bios.s
Normal file
54
bootloaderalt/source/read_bios.s
Normal file
@ -0,0 +1,54 @@
|
||||
#include <nds/asminc.h>
|
||||
|
||||
@This code comes from a post by CaitSith2 at gbadev.org - THANKS!!
|
||||
@
|
||||
@Code to dump the complete Nintendo DS ARM7 bios, including the
|
||||
@first 0x1204 bytes residing in the secure area.
|
||||
@
|
||||
@The ARM7 bios has read protection where 0x(Word)[FFFF(Half word)[FF(Byte)[FF]]]
|
||||
@is returned, if any reads are attempted while PC is outside the arm7 bios range.
|
||||
@
|
||||
@Additionally, if the PC is outside the 0x0000 - 0x1204 range, that range of the bios
|
||||
@is completely locked out from reading.
|
||||
|
||||
|
||||
@ void readBios (u8* dest, u32 src, u32 size)
|
||||
|
||||
.arm
|
||||
|
||||
BEGIN_ASM_FUNC readBios
|
||||
adr r3,bios_dump+1
|
||||
bx r3
|
||||
.thumb
|
||||
|
||||
bios_dump:
|
||||
push {r4-r7,lr} @Even though we don't use R7, the code we are jumping to is going
|
||||
@trash R7, therefore, we must save it.
|
||||
mov r5, r1 @ src
|
||||
sub r1, r2, #1 @ size
|
||||
mov r2, r0 @ dest
|
||||
ldr r0,=0x5ED @The code that will be made to read the full bios resides here.
|
||||
|
||||
loop:
|
||||
mov r6,#0x12 @We Subtract 12 from the location we wish to read
|
||||
sub r3,r1,r6 @because the code at 0x5EC is LDRB R3, [R3,#0x12]
|
||||
add r3, r3, r5
|
||||
adr r6,ret
|
||||
push {r2-r6} @The line of code at 0x5EE is POP {R2,R4,R6,R7,PC}
|
||||
bx r0
|
||||
.align
|
||||
|
||||
ret:
|
||||
strb r3,[r2,r1] @Store the read byte contained in r3, to SRAM.
|
||||
sub r1,#1 @Subtract 1
|
||||
bpl loop @And branch as long as R1 doesn't roll into -1 (0xFFFFFFFF).
|
||||
|
||||
pop {r4-r7} @Restore the saved registers
|
||||
pop {r3} @and return.
|
||||
bx r3
|
||||
|
||||
.END
|
||||
|
||||
@The exact code that resides at 0x5EC (secure area range) of the arm7 bios.
|
||||
@ROM:000005EC 9B 7C LDRB R3, [R3,#0x12]
|
||||
@ROM:000005EE D4 BD POP {R2,R4,R6,R7,PC}
|
81
bootloaderalt/source/reset.arm7.s
Normal file
81
bootloaderalt/source/reset.arm7.s
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 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/>.
|
||||
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.arm
|
||||
@---------------------------------------------------------------------------------
|
||||
.global arm7_reset
|
||||
.type arm7_reset STT_FUNC
|
||||
@---------------------------------------------------------------------------------
|
||||
arm7_reset:
|
||||
@---------------------------------------------------------------------------------
|
||||
mrs r0, cpsr @ cpu interrupt disable
|
||||
orr r0, r0, #0x80 @ (set i flag)
|
||||
msr cpsr, r0
|
||||
|
||||
ldr r0, =0x380FFFC @ irq vector
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
sub r0, r0, #4 @ IRQ1 Check Bits
|
||||
str r1, [r0]
|
||||
sub r0, r0, #4 @ IRQ2 Check Bits
|
||||
str r1, [r0]
|
||||
|
||||
bic r0, r0, #0x7f
|
||||
|
||||
msr cpsr_c, #0xd3 @ svc mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #64
|
||||
msr cpsr_c, #0xd2 @ irq mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #512
|
||||
msr cpsr_c, #0xdf @ system mode
|
||||
mov sp, r0
|
||||
|
||||
mov r12, #0x04000000
|
||||
add r12, r12, #0x180
|
||||
|
||||
@ while (ipcRecvState() != ARM9_RESET);
|
||||
mov r0, #2
|
||||
bl waitsync
|
||||
@ ipcSendState(ARM7_RESET)
|
||||
mov r0, #0x200
|
||||
strh r0, [r12]
|
||||
|
||||
@ while(ipcRecvState() != ARM9_BOOT);
|
||||
mov r0, #0
|
||||
bl waitsync
|
||||
@ ipcSendState(ARM7_BOOT)
|
||||
strh r0, [r12]
|
||||
|
||||
ldr r0,=0x27FFE34
|
||||
|
||||
ldr r0,[r0]
|
||||
bx r0
|
||||
|
||||
.pool
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
waitsync:
|
||||
@---------------------------------------------------------------------------------
|
||||
ldrh r1, [r12]
|
||||
and r1, r1, #0x000f
|
||||
cmp r0, r1
|
||||
bne waitsync
|
||||
bx lr
|
135
bootloaderalt/source/reset.arm9.s
Normal file
135
bootloaderalt/source/reset.arm9.s
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
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 arm9_reset
|
||||
.type arm9_reset STT_FUNC
|
||||
@---------------------------------------------------------------------------------
|
||||
arm9_reset:
|
||||
@---------------------------------------------------------------------------------
|
||||
mrs r0, cpsr @ cpu interrupt disable
|
||||
orr r0, r0, #0x80 @ (set i flag)
|
||||
msr cpsr, r0
|
||||
|
||||
@ 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]
|
||||
|
||||
bic r0, r0, #0x7f
|
||||
|
||||
msr cpsr_c, #0xd3 @ svc mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #64
|
||||
msr cpsr_c, #0xd2 @ irq mode
|
||||
mov sp, r0
|
||||
sub r0, r0, #4096
|
||||
msr cpsr_c, #0xdf @ system mode
|
||||
mov sp, r0
|
||||
|
||||
mov r12, #0x04000000
|
||||
add r12, r12, #0x180
|
||||
|
||||
@ ipcSendState(ARM9_RESET)
|
||||
mov r0, #0x200
|
||||
strh r0, [r12]
|
||||
@ while (ipcRecvState() != ARM7_RESET);
|
||||
mov r0, #2
|
||||
bl waitsync
|
||||
|
||||
@ ipcSendState(ARM9_BOOT)
|
||||
mov r0, #0
|
||||
strh r0, [r12]
|
||||
@ while (ipcRecvState() != ARM7_BOOT);
|
||||
bl waitsync
|
||||
|
||||
ldr r10, =0x27FFE24
|
||||
ldr r2, [r10]
|
||||
|
||||
@ Switch MPU to startup default
|
||||
ldr r0, =0x00012078
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
bx r2
|
||||
|
||||
.pool
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
waitsync:
|
||||
@---------------------------------------------------------------------------------
|
||||
ldrh r1, [r12]
|
||||
and r1, r1, #0x000f
|
||||
cmp r0, r1
|
||||
bne waitsync
|
||||
bx lr
|
||||
|
||||
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 0x027ff017 @ 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
|
||||
itcm_reset_code_end:
|
126
bootloaderalt/source/tonccpy.c
Normal file
126
bootloaderalt/source/tonccpy.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include <stddef.h>
|
||||
#include "tonccpy.h"
|
||||
//# tonccpy.c
|
||||
|
||||
//! VRAM-safe cpy.
|
||||
/*! This version mimics memcpy in functionality, with
|
||||
the benefit of working for VRAM as well. It is also
|
||||
slightly faster than the original memcpy, but faster
|
||||
implementations can be made.
|
||||
\param dst Destination pointer.
|
||||
\param src Source pointer.
|
||||
\param size Fill-length in bytes.
|
||||
\note The pointers and size need not be word-aligned.
|
||||
*/
|
||||
void tonccpy(void *dst, const void *src, uint size) {
|
||||
|
||||
if(size==0 || dst==NULL || src==NULL) { return; }
|
||||
|
||||
uint count;
|
||||
u16 *dst16; // hword destination
|
||||
u8 *src8; // byte source
|
||||
|
||||
// Ideal case: copy by 4x words. Leaves tail for later.
|
||||
if( ((u32)src|(u32)dst)%4==0 && size>=4) {
|
||||
u32 *src32= (u32*)src, *dst32= (u32*)dst;
|
||||
|
||||
count= size/4;
|
||||
uint tmp= count&3;
|
||||
count /= 4;
|
||||
|
||||
// Duff's Device, good friend!
|
||||
// Added fall through attribute to silance the compiler about this. ;)
|
||||
switch(tmp) {
|
||||
do { *dst32++ = *src32++; // fallthrough
|
||||
case 3: *dst32++ = *src32++; // fallthrough
|
||||
case 2: *dst32++ = *src32++; // fallthrough
|
||||
case 1: *dst32++ = *src32++; // fallthrough
|
||||
case 0: ;} while(count--); // fallthrough
|
||||
}
|
||||
|
||||
// Check for tail
|
||||
size &= 3;
|
||||
if(size == 0) { return; }
|
||||
src8= (u8*)src32;
|
||||
dst16= (u16*)dst32;
|
||||
} else {
|
||||
// Unaligned.
|
||||
uint dstOfs= (u32)dst&1;
|
||||
src8= (u8*)src;
|
||||
dst16= (u16*)(dst-dstOfs);
|
||||
|
||||
// Head: 1 byte.
|
||||
if(dstOfs != 0) {
|
||||
*dst16= (*dst16 & 0xFF) | *src8++<<8;
|
||||
dst16++;
|
||||
if(--size==0) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
// Unaligned main: copy by 2x byte.
|
||||
count= size/2;
|
||||
while(count--) {
|
||||
*dst16++ = src8[0] | src8[1]<<8;
|
||||
src8 += 2;
|
||||
}
|
||||
|
||||
// Tail: 1 byte.
|
||||
if(size&1) { *dst16= (*dst16 &~ 0xFF) | *src8; }
|
||||
}
|
||||
//# toncset.c
|
||||
|
||||
//! VRAM-safe memset, internal routine.
|
||||
/*! This version mimics memset in functionality, with
|
||||
the benefit of working for VRAM as well. It is also
|
||||
slightly faster than the original memset.
|
||||
\param dst Destination pointer.
|
||||
\param fill Word to fill with.
|
||||
\param size Fill-length in bytes.
|
||||
\note The \a dst pointer and \a size need not be
|
||||
word-aligned. In the case of unaligned fills, \a fill
|
||||
will be masked off to match the situation.
|
||||
*/
|
||||
void __toncset(void *dst, u32 fill, uint size) {
|
||||
if(size==0 || dst==NULL) { return; }
|
||||
|
||||
uint left= (u32)dst&3;
|
||||
u32 *dst32= (u32*)(dst-left);
|
||||
u32 count, mask;
|
||||
|
||||
// Unaligned head.
|
||||
if(left != 0) {
|
||||
// Adjust for very small stint.
|
||||
if(left+size<4) {
|
||||
mask= BIT_MASK(size*8)<<(left*8);
|
||||
*dst32= (*dst32 &~ mask) | (fill & mask);
|
||||
return;
|
||||
}
|
||||
|
||||
mask= BIT_MASK(left*8);
|
||||
*dst32= (*dst32 & mask) | (fill&~mask);
|
||||
dst32++;
|
||||
size -= 4-left;
|
||||
}
|
||||
|
||||
// Main stint.
|
||||
count= size/4;
|
||||
uint tmp= count&3;
|
||||
count /= 4;
|
||||
|
||||
// Added fall through attribute to silance the compiler about this. ;)
|
||||
switch(tmp) {
|
||||
do { *dst32++ = fill; // fallthrough
|
||||
case 3: *dst32++ = fill; // fallthrough
|
||||
case 2: *dst32++ = fill; // fallthrough
|
||||
case 1: *dst32++ = fill; // fallthrough
|
||||
case 0: ;} while(count--); // fallthrough
|
||||
}
|
||||
|
||||
// Tail
|
||||
size &= 3;
|
||||
if(size) {
|
||||
mask= BIT_MASK(size*8);
|
||||
*dst32= (*dst32 &~ mask) | (fill & mask);
|
||||
}
|
||||
}
|
||||
|
43
bootloaderalt/source/tonccpy.h
Normal file
43
bootloaderalt/source/tonccpy.h
Normal file
@ -0,0 +1,43 @@
|
||||
//# Stuff you may not have yet.
|
||||
|
||||
#ifndef TONCCPY_H
|
||||
#define TONCCPY_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
typedef unsigned int uint;
|
||||
#define BIT_MASK(len) ( (1<<(len))-1 )
|
||||
static inline u32 quad8(u16 x) { x |= x<<8; return x | x<<16; }
|
||||
|
||||
|
||||
//# Declarations and inlines.
|
||||
|
||||
void tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void __toncset(void *dst, u32 fill, uint size);
|
||||
static inline void toncset(void *dst, u8 src, uint size);
|
||||
static inline void toncset16(void *dst, u16 src, uint size);
|
||||
static inline void toncset32(void *dst, u32 src, uint size);
|
||||
|
||||
|
||||
//! VRAM-safe memset, byte version. Size in bytes.
|
||||
static inline void toncset(void *dst, u8 src, uint size)
|
||||
{ __toncset(dst, quad8(src), size); }
|
||||
|
||||
//! VRAM-safe memset, halfword version. Size in hwords.
|
||||
static inline void toncset16(void *dst, u16 src, uint size)
|
||||
{ __toncset(dst, src|src<<16, size*2); }
|
||||
|
||||
//! VRAM-safe memset, word version. Size in words.
|
||||
static inline void toncset32(void *dst, u32 src, uint size)
|
||||
{ __toncset(dst, src, size*4); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user