Finally fixed 4swordshax by loading a heavily stripped down payload (minitwlpayload, ~5.4KB) from dataPub:/, which is itself based off nds-hb-menu's ARM7 bootloader.

This commit is contained in:
fincs 2016-11-01 01:02:57 +01:00
parent 8bad190f45
commit 20fe8d68ca
23 changed files with 2787 additions and 32 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
build/
exploits/generictwlpayload/**/*.bin
exploits/minitwlpayload/**/*.bin
*~
*.elf
*.dat
*.lz

View File

@ -1,9 +1,9 @@
This is the *source* for DSi exploits/etc for DSiWare savedata. This repo is originally from 2011. These DSiWare exploits were already released in binary-only form(2011). The only exception is 4swordshax from 2011, which wasn't publicly available [until](https://github.com/yellows8/3ds_dsiwarehax_installer) 2016 since it wasn't usable on DSi without(?) a nandmod(this is the only DSiWareHax that triggers in about 1-second after app boot before any gfx is displayed). There's currently no known way to successfully load the payload from 4swordshax, hence it will just display a red sub-screen on failure.
This is the *source* for DSi exploits/etc for DSiWare savedata. This repo is originally from 2011. These DSiWare exploits were already released in binary-only form(2011). The only exception is 4swordshax from 2011, which wasn't publicly available [until](https://github.com/yellows8/3ds_dsiwarehax_installer) 2016 since it wasn't usable on DSi without(?) a nandmod(this is the only DSiWareHax that triggers in about 1-second after app boot before any gfx is displayed).
If you want a prebuilt binary for generictwlpayload(it can't be completely built from this repo), check the released exploit saveimages(for example [here](https://github.com/yellows8/3ds_dsiwarehax_installer)).
Credits:
* See repo description text.
* polarssl
* This uses code from/based on libnds/bootmii-MINI.
* This uses code from/based on libnds/bootmii-MINI/nds-hb-menu.
* ...

View File

@ -15,6 +15,7 @@
#define REGION_EUR 56
#define REG_BASE 0x04000000
#define PAYLOAD_ADDR 0x02200000
#define FS_InitCtx 0x20102d4
#define FS_Open 0x2010b1c
@ -43,7 +44,7 @@ _start:
@ 4swords has two savefiles, savedata/all.dat and savedata/backup.dat. When loading one fails,(in this case larger than normal filesize) it will fallback to loading the other savefile. It will then continue without error as long as loading one of the saves worked.(it will stop loading the save *after* it reads the save into memory with the filesize, when the filesize is too large. by then it's too late to stop haxx, it seems even if *both* saves were corrupted the attacked heap stuff below would still be used & exploited before their "corrupted save" delete+recreate code executes.)
.word 0, 0
.word HEAPCTX_ADR @ Adr of the next word. Starting with that adr, we overwrite a class with a vtable, but that class doesn't matter since it seems to be only used before loading the save.
.word HEAPCTX_ADR @ Adr of the next word. Starting with that adr, we overwrite a class with a vtable, but that class does not matter since it seems to be only used before loading the save.
.word 0 @ Without this padding, the title will overwrite heapctx+0x34 with a vtable ptr after the savedata was loaded.
.word 0 @ Without this here, the title would overwrite heapctx+0x24+12 with a vtable ptr.
.word HEAPCTX_ADR+4 @ This is actually a ptr to the heapctx.
@ -88,18 +89,17 @@ mov r2, #1
ldr r4, =FS_Open
blx r4
cmp r0, #0
beq gfxdisp
bne success
mov r6, #0x1f
bl gfxdisp
1: b 1b
success:
mov r0, sp
mov r3, #0x0020
lsl r3, #4
add r3, #0x20
lsl r3, #16 @ 0x02200000
mov r7, r3
mov r1, r3
mov r2, #0xd4
lsl r2, #8
add r2, #4 @ 0xd404
ldr r1, =PAYLOAD_ADDR
mov r7, r1
ldr r2, =PAYLOAD_SIZE
ldr r4, =FS_Read
blx r4
@ -111,8 +111,10 @@ blx DC_FlushAll
blx DC_InvalidateAll
blx IC_InvalidateAll
mov r1, r7
bx r1
push {r7}
ldr r6, =0x3af3
bl gfxdisp
pop {pc}
gfxdisp:
ldr r7, =REG_BASE
@ -149,12 +151,10 @@ mov r1, #0x84
strb r1, [r0,#0x02]
ldr r4, =0x05000000 @ engine A palette
mov r1, #0x1f
str r1, [r4]
str r6, [r4]
ldr r5, =0x400
str r1, [r4, r5] @ engine B palette
code_end:
b code_end
str r6, [r4, r5] @ engine B palette
bx lr
.pool
.align 2
@ -203,12 +203,5 @@ IC_InvalidateAll: @ From libnds.
bx lr
payloadpath:
#if REGCODE==REGION_USA
.string "nand:/title/00030004/4B513945/data/banner.new"
#elif REGCODE==REGION_EUR
.string "nand:/title/00030004/4B513956/data/banner.new"
#endif
.string "dataPub:/savedata/payload.dat"
.align 2
.space (_start + 0x1c00) - .

View File

@ -20,18 +20,21 @@ endif
all: all.dat
clean:
rm -f $(HAXNAME).elf all.dat $(TID)$(REGCODE)hax_crypt.sav.$(HAXVER) $(HAXNAME)_crypt.ban.$(HAXVER) $(TID)$(REGCODE).tmd.sha1 $(TID)$(REGCODE)hax.savedata.sha1 $(HAXNAME).banner.sha1
@make clean -C ../minitwlpayload
rm -f $(HAXNAME).elf all.dat ../minitwlpayload/payload.dat $(TID)$(REGCODE)hax_crypt.sav.$(HAXVER) $(HAXNAME)_crypt.ban.$(HAXVER) $(TID)$(REGCODE).tmd.sha1 $(TID)$(REGCODE)hax.savedata.sha1 $(HAXNAME).banner.sha1
all.dat: $(HAXNAME).elf
arm-none-eabi-objcopy -O binary $(HAXNAME).elf all.dat
cp $(TID)$(REGCODE)in.savedata $(TID)$(REGCODE)hax.savedata
sudo mount -o loop $(TID)$(REGCODE)hax.savedata $(HAXNAME)
sudo cp ./all.dat $(HAXNAME)/savedata/all.dat
sudo cp ../minitwlpayload/payload.dat $(HAXNAME)/savedata/payload.dat
sudo umount $(HAXNAME)
cp ../generictwlpayload/generictwlpayload.bin $(TID)$(REGCODE)hax.banner_new
cp $(TID)$(REGCODE)hax.savedata public.sav
../dumprawsav/dumprawsav --insav=$(CURDIR)/$(TID)$(REGCODE)hax.savedata --inban=$(CURDIR)/$(HAXNAME).banner --cryptsav=$(CURDIR)/$(TID)$(REGCODE)hax_crypt.sav.$(HAXVER) --cryptban=$(CURDIR)/$(HAXNAME)_crypt.ban.$(HAXVER) --hashsav=$(TID)$(REGCODE)hax.savedata.sha1 --hashban=$(HAXNAME).banner.sha1
$(HAXNAME).elf: $(HAXNAME).s
arm-none-eabi-gcc -x assembler-with-cpp -nostartfiles -nostdlib -DREGCODE=$(REGCODE) $(HAXNAME).s -o $(HAXNAME).elf
$(HAXNAME).elf: $(HAXNAME).s ../minitwlpayload/payload.dat
arm-none-eabi-gcc -x assembler-with-cpp -nostartfiles -nostdlib -DREGCODE=$(REGCODE) -DPAYLOAD_SIZE=`stat -L -c %s ../minitwlpayload/payload.dat` $(HAXNAME).s -o $(HAXNAME).elf
../minitwlpayload/payload.dat:
@make -C ../minitwlpayload

View File

@ -0,0 +1,168 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files embedded using bin2o
# GRAPHICS is a list of directories containing image files to be converted with grit
#---------------------------------------------------------------------------------
TARGET := payload
BUILD := build
SOURCES := source
INCLUDES := include build
DATA := data
GRAPHICS := gfx
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -Os\
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffunction-sections -save-temps \
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9 $(DEFINES)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) $(DEFINES)
LDFLAGS = -nostartfiles -T../stub.ld -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--gc-sections,--use-blx
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
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 OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := ndsloader.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(PNGFILES:.png=.o) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
icons := $(wildcard *.bmp)
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
else
ifneq (,$(findstring icon.bmp,$(icons)))
export GAME_ICON := $(CURDIR)/icon.bmp
endif
endif
.PHONY: all bootloader $(BUILD) clean
all: bootloader $(BUILD)
bootloader: $(DATA)
@make -C bootloader
$(DATA):
@mkdir -p $@
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@make clean -C bootloader
@rm -fr $(BUILD) $(DATA) $(TARGET).elf $(TARGET).dat
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).dat : $(OUTPUT).elf
@$(OBJCOPY) -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
$(bin2o)
#---------------------------------------------------------------------------------
%.nds.o : %.nds
#---------------------------------------------------------------------------------
@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
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,114 @@
#---------------------------------------------------------------------------------
.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 := ndsloader
BUILD := build
SOURCES := source source/patches
INCLUDES := build
SPECS := specs
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -Os\
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffunction-sections -save-temps\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM7
ASFLAGS := -g $(ARCH)
LDFLAGS = -nostartfiles -T $(TOPDIR)/load.ld -g $(ARCH) -Wl,-Map,$(TARGET).map -Wl,--gc-sections
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)/../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) $(LOADBIN) $(LOADELF)
#---------------------------------------------------------------------------------
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)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,198 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
MEMORY {
vram : ORIGIN = 0x06000000, LENGTH = 128K
}
__vram_start = ORIGIN(vram);
__vram_top = ORIGIN(vram)+ LENGTH(vram);
__sp_irq = __vram_top - 0x60;
__sp_svc = __sp_irq - 0x100;
__sp_usr = __sp_svc - 0x100;
__irq_flags = __vram_top - 8;
__irq_vector = __vram_top - 4;
SECTIONS
{
.init :
{
__text_start = . ;
KEEP (*(.init))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.plt :
{
*(.plt)
} >vram = 0xff
.text : /* ALIGN (4): */
{
*(.text*)
*(.stub)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.fini :
{
KEEP (*(.fini))
} >vram =0xff
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >vram
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >vram
__exidx_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { KEEP (*(.preinit_array)) } >vram = 0xff
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { KEEP (*(.init_array)) } >vram = 0xff
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { KEEP (*(.fini_array)) } >vram = 0xff
PROVIDE (__fini_array_end = .);
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram = 0xff
.jcr : { KEEP (*(.jcr)) } >vram = 0
.got : { *(.got.plt) *(.got) } >vram = 0
.vram ALIGN(4) :
{
__vram_start = ABSOLUTE(.) ;
*(.vram)
*vram.*(.text)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__vram_end = ABSOLUTE(.) ;
} >vram = 0xff
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >vram = 0xff
.bss ALIGN(4) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >vram
__bss_end = . ;
__bss_end__ = . ;
_end = . ;
__end__ = . ;
PROVIDE (end = _end);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.stack 0x80000 : { _stack = .; *(.stack) }
/* These must appear regardless of . */
}

View File

@ -0,0 +1,60 @@
/*-----------------------------------------------------------------
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
mov r9, #0x03000000
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

View File

@ -0,0 +1,114 @@
#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"
static inline void debug_color(int r, int g, int b)
{
u16 clr = RGB15(r,g,b);
*(vu32*)0x05000000 = clr;
*(vu32*)0x05000400 = clr;
}
/*-------------------------------------------------------------------------
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, reg;
if (*(vu32*)(0x02FFE000-4))
debug_color(0,0,31); // blue
else
debug_color(31,15,15); // light red
//clear out ARM9 DMA channels
/* --removed-- already done by other code
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;
for(reg=0; reg<0x1c; reg+=4)*((u32*)(0x04004104 + ((i*0x1c)+reg))) = 0;//Reset NDMA.
}
*/
VRAM_CR = (VRAM_CR & 0xffff0000) | 0x00008080 ;
u16 *mainregs = (u16*)0x04000000;
u16 *subregs = (u16*)0x04001000;
for (i=0; i<43; i++) {
mainregs[i] = 0;
subregs[i] = 0;
}
REG_DISPSTAT = 0;
VRAM_A_CR = 0;
VRAM_B_CR = 0;
// Don't mess with the ARM7's VRAM
// VRAM_C_CR = 0;
VRAM_D_CR = 0;
VRAM_E_CR = 0;
VRAM_F_CR = 0;
VRAM_G_CR = 0;
VRAM_H_CR = 0;
VRAM_I_CR = 0;
/* --removed-- already done by other code
REG_POWERCNT = 0x820F;
//set shared ram to ARM7
WRAM_CR = 0x03;
REG_EXMEMCNT = 0xE880;
*/
// 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)
{
debug_color(15,15,31); // light blue
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);
}

View File

@ -0,0 +1,13 @@
.text
.align 4
.thumb
@---------------------------------------------------------------------------------
.global swiDelay
.thumb_func
@---------------------------------------------------------------------------------
swiDelay:
@---------------------------------------------------------------------------------
swi 0x03
bx lr

View File

@ -0,0 +1,293 @@
/*-----------------------------------------------------------------
boot.c
BootLoader
Loads a file into memory and runs it
All resetMemory and startBinary functions are based
on the MultiNDS loader by Darkain.
Original source available at:
http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp
License:
Copyright (C) 2005 Michael "Chishm" Chisholm
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
If you use this code, please give due credit and email me about your
project at chishm@hotmail.com
Helpful information:
This code runs from VRAM bank C on ARM7
------------------------------------------------------------------*/
#include <nds/ndstypes.h>
#include <nds/dma.h>
#include <nds/system.h>
#include <nds/interrupts.h>
#include <nds/timers.h>
#define ARM9
#undef ARM7
#include <nds/memory.h>
#include <nds/arm9/video.h>
#include <nds/arm9/input.h>
#undef ARM9
#define ARM7
#include <nds/arm7/audio.h>
#include "fat.h"
#include "card.h"
#include "boot.h"
void arm7clearRAM();
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Important things
#define TEMP_MEM 0x02FFE000
#define NDS_HEAD 0x02FFFE00
#define TEMP_ARM9_START_ADDRESS (*(vu32*)0x02FFFFF4)
const char* bootName = "BOOT.NDS";
extern unsigned long _start;
extern unsigned long argStart;
extern unsigned long argSize;
#ifdef USE_FIRMWARE_READ
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 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;
}
#endif
static inline void copyLoop (u32* dest, const u32* src, u32 size) {
size = (size +3) & ~3;
do {
*dest++ = *src++;
} while (size -= 4);
}
//#define resetCpu() __asm volatile("\tswi 0x000000\n");
/*-------------------------------------------------------------------------
passArgs_ARM7
Copies the command line arguments to the end of the ARM9 binary,
then sets a flag in memory for the loaded NDS to use
--------------------------------------------------------------------------*/
void passArgs_ARM7 (void) {
u32 ARM9_DST = *((u32*)(NDS_HEAD + 0x028));
u32 ARM9_LEN = *((u32*)(NDS_HEAD + 0x02C));
u32* argSrc;
u32* argDst;
if (!argStart || !argSize) return;
argSrc = (u32*)(argStart + (int)&_start);
argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned
copyLoop(argDst, argSrc, argSize);
__system_argv->argvMagic = ARGV_MAGIC;
__system_argv->commandLine = (char*)argDst;
__system_argv->length = argSize;
}
/*-------------------------------------------------------------------------
resetMemory_ARM7
Clears all of the NDS's RAM that is visible to the ARM7
Written by Darkain.
Modified by Chishm:
* Added STMIA clear mem loop
--------------------------------------------------------------------------*/
void resetMemory_ARM7 (void)
{
int i,reg;
#ifdef USE_FIRMWARE_READ
u8 settings1, settings2;
u32 settingsOffset = 0;
#endif
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;
REG_SOUNDBIAS = 0x0200; //Fix bad sounds after soft reset
for (i=0; i<0x20; i+=4) //Clear sound capture hw.
*(vu32*)(0x04000508+i) = 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;
for(reg=0; reg<0x1c; reg+=4)*((u32*)(0x04004104 + ((i*0x1c)+reg))) = 0;//Reset NDMA.
}
arm7clearRAM();
REG_IE = 0;
REG_IF = ~0;
REG_AUXIE = 0;
REG_AUXIF = ~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
#ifdef USE_FIRMWARE_READ
// 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);
}
#endif
}
void loadBinary_ARM7 (u32 fileCluster)
{
u32 ndsHeader[0x170>>2];
// read NDS header
fileRead ((char*)ndsHeader, fileCluster, 0, 0x170);
// read ARM9 info from NDS header
u32 ARM9_SRC = ndsHeader[0x020>>2];
char* ARM9_DST = (char*)ndsHeader[0x028>>2];
u32 ARM9_LEN = ndsHeader[0x02C>>2];
// read ARM7 info from NDS header
u32 ARM7_SRC = ndsHeader[0x030>>2];
char* ARM7_DST = (char*)ndsHeader[0x038>>2];
u32 ARM7_LEN = ndsHeader[0x03C>>2];
// Load binaries into memory
fileRead(ARM9_DST, fileCluster, ARM9_SRC, ARM9_LEN);
fileRead(ARM7_DST, fileCluster, ARM7_SRC, ARM7_LEN);
// first copy the header to its proper location, excluding
// the ARM9 start address, so as not to start it
TEMP_ARM9_START_ADDRESS = ndsHeader[0x024>>2]; // Store for later
ndsHeader[0x024>>2] = 0;
dmaCopyWords(3, (void*)ndsHeader, (void*)NDS_HEAD, 0x170);
}
/*-------------------------------------------------------------------------
startBinary_ARM7
Jumps to the ARM7 NDS binary in sync with the display and ARM9
Written by Darkain.
Modified by Chishm:
* Removed MultiNDS specific stuff
--------------------------------------------------------------------------*/
void startBinary_ARM7 (void) {
REG_IME=0;
while(REG_VCOUNT!=191);
while(REG_VCOUNT==191);
// copy NDS ARM9 start address into the header, starting ARM9
*((vu32*)0x02FFFE24) = TEMP_ARM9_START_ADDRESS;
ARM9_START_FLAG = 1;
// Start ARM7
VoidFn arm7code = *(VoidFn*)(0x2FFFE34);
arm7code();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Main function
int main (void) {
// Init card
bool fs_success = FAT_InitFiles();
u32 fileCluster = CLUSTER_FREE;
if (fs_success)
{
// Get cluster of boot file
fileCluster = getBootFileCluster("BOOT.NDS");
fs_success = fileCluster != CLUSTER_FREE;
}
// ARM9 clears its memory part 2
// copy ARM9 function to RAM, and make the ARM9 jump to it
*(vu32*)(TEMP_MEM-4) = fs_success;
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);
if (!fs_success)
return -1;
// 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);
// Pass command line arguments to loaded program
passArgs_ARM7();
startBinary_ARM7();
return 0;
}

View 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_

View File

@ -0,0 +1,49 @@
/*-----------------------------------------------------------------
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
#define BYTES_PER_SECTOR 512
void sdmmc_controller_init();
int sdmmc_sdcard_init();
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out);
static inline bool CARD_StartUp (void) {
sdmmc_controller_init();
return sdmmc_sdcard_init() == 0;
}
static inline bool CARD_IsInserted (void) {
return true;
}
static inline bool CARD_ReadSectors (u32 sector, int count, void *buffer) {
return sdmmc_sdcard_readsectors(sector, count, buffer) == 0;
}
static inline bool CARD_ReadSector (u32 sector, void *buffer) {
return sdmmc_sdcard_readsectors(sector, 1, buffer) == 0;
}
#endif // CARD_H

View File

@ -0,0 +1,587 @@
/*-----------------------------------------------------------------
fat.c
NDS MP
GBAMP NDS Firmware Hack Version 2.12
An NDS aware firmware patch for the GBA Movie Player.
By Michael Chisholm (Chishm)
Filesystem code based on GBAMP_CF.c by Chishm (me).
License:
Copyright (C) 2005 Michael "Chishm" Chisholm
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
If you use this code, please give due credit and email me about your
project at chishm@hotmail.com
------------------------------------------------------------------*/
#include "fat.h"
#include "card.h"
//---------------------------------------------------------------
// FAT constants
#define FILE_LAST 0x00
#define FILE_FREE 0xE5
#define ATTRIB_ARCH 0x20
#define ATTRIB_DIR 0x10
#define ATTRIB_LFN 0x0F
#define ATTRIB_VOL 0x08
#define ATTRIB_HID 0x02
#define ATTRIB_SYS 0x04
#define ATTRIB_RO 0x01
#define FAT16_ROOT_DIR_CLUSTER 0x00
// File Constants
#ifndef EOF
#define EOF -1
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif
//-----------------------------------------------------------------
// FAT constants
#define CLUSTER_EOF_16 0xFFFF
#define ATTRIB_ARCH 0x20
#define ATTRIB_DIR 0x10
#define ATTRIB_LFN 0x0F
#define ATTRIB_VOL 0x08
#define ATTRIB_HID 0x02
#define ATTRIB_SYS 0x04
#define ATTRIB_RO 0x01
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Data Structures
#define __PACKED __attribute__ ((__packed__))
// Boot Sector - must be packed
typedef struct
{
u8 jmpBoot[3];
u8 OEMName[8];
// BIOS Parameter Block
u16 bytesPerSector;
u8 sectorsPerCluster;
u16 reservedSectors;
u8 numFATs;
u16 rootEntries;
u16 numSectorsSmall;
u8 mediaDesc;
u16 sectorsPerFAT;
u16 sectorsPerTrk;
u16 numHeads;
u32 numHiddenSectors;
u32 numSectors;
union // Different types of extended BIOS Parameter Block for FAT16 and FAT32
{
struct
{
// Ext BIOS Parameter Block for FAT16
u8 driveNumber;
u8 reserved1;
u8 extBootSig;
u32 volumeID;
u8 volumeLabel[11];
u8 fileSysType[8];
// Bootcode
u8 bootCode[448];
} fat16;
struct
{
// FAT32 extended block
u32 sectorsPerFAT32;
u16 extFlags;
u16 fsVer;
u32 rootClus;
u16 fsInfo;
u16 bkBootSec;
u8 reserved[12];
// Ext BIOS Parameter Block for FAT16
u8 driveNumber;
u8 reserved1;
u8 extBootSig;
u32 volumeID;
u8 volumeLabel[11];
u8 fileSysType[8];
// Bootcode
u8 bootCode[420];
} fat32;
} extBlock;
__PACKED u16 bootSig;
} __PACKED BOOT_SEC;
// Directory entry - must be packed
typedef struct
{
u8 name[8];
u8 ext[3];
u8 attrib;
u8 reserved;
u8 cTime_ms;
u16 cTime;
u16 cDate;
u16 aDate;
u16 startClusterHigh;
u16 mTime;
u16 mDate;
u16 startCluster;
u32 fileSize;
} __PACKED DIR_ENT;
// File information - no need to pack
typedef struct
{
u32 firstCluster;
u32 length;
u32 curPos;
u32 curClus; // Current cluster to read from
int curSect; // Current sector within cluster
int curByte; // Current byte within sector
char readBuffer[512]; // Buffer used for unaligned reads
u32 appClus; // Cluster to append to
int appSect; // Sector within cluster for appending
int appByte; // Byte within sector for appending
bool read; // Can read from file
bool write; // Can write to file
bool append;// Can append to file
bool inUse; // This file is open
u32 dirEntSector; // The sector where the directory entry is stored
int dirEntOffset; // The offset within the directory sector
} FAT_FILE;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Global Variables
// _VARS_IN_RAM variables are stored in the largest section of WRAM
// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA
// Locations on card
int discRootDir;
int discRootDirClus;
int discFAT;
int discSecPerFAT;
int discNumSec;
int discData;
int discBytePerSec;
int discSecPerClus;
int discBytePerClus;
enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} discFileSystem;
// Global sector buffer to save on stack space
unsigned char globalBuffer[BYTES_PER_SECTOR];
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//FAT routines
u32 FAT_ClustToSect (u32 cluster) {
return (((cluster-2) * discSecPerClus) + discData);
}
/*-----------------------------------------------------------------
FAT_NextCluster
Internal function - gets the cluster linked from input cluster
-----------------------------------------------------------------*/
u32 FAT_NextCluster(u32 cluster)
{
u32 nextCluster = CLUSTER_FREE;
u32 sector;
int offset;
switch (discFileSystem)
{
#ifdef SUPPORT_OLD_FAT
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;
#endif
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 (void)
{
int i;
int bootSector;
BOOT_SEC* bootSec;
if (!CARD_StartUp())
{
return (false);
}
// Read first sector of card
if (!CARD_ReadSector (0, globalBuffer))
{
return false;
}
// Check if there is a FAT string, which indicates this is a boot sector
if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T'))
{
bootSector = 0;
}
// Check for FAT32
else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T'))
{
bootSector = 0;
}
else // This is an MBR
{
// Find first valid partition from MBR
// First check for an active partition
for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10);
// If it didn't find an active partition, search for any valid partition
if (i == 0x1FE)
for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10);
// Go to first valid partition
if ( i != 0x1FE) // Make sure it found a partition
{
bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F);
} else {
bootSector = 0; // No partition found, assume this is a MBR free disk
}
}
// Read in boot sector
bootSec = (BOOT_SEC*) globalBuffer;
CARD_ReadSector (bootSector, bootSec);
// Store required information about the file system
if (bootSec->sectorsPerFAT != 0)
{
discSecPerFAT = bootSec->sectorsPerFAT;
}
else
{
discSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32;
}
if (bootSec->numSectorsSmall != 0)
{
discNumSec = bootSec->numSectorsSmall;
}
else
{
discNumSec = bootSec->numSectors;
}
discBytePerSec = BYTES_PER_SECTOR; // Sector size is redefined to be 512 bytes
discSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTES_PER_SECTOR;
discBytePerClus = discBytePerSec * discSecPerClus;
discFAT = bootSector + bootSec->reservedSectors;
discRootDir = discFAT + (bootSec->numFATs * discSecPerFAT);
discData = discRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / BYTES_PER_SECTOR);
if ((discNumSec - discData) / bootSec->sectorsPerCluster < 4085)
{
discFileSystem = FS_FAT12;
}
else if ((discNumSec - discData) / bootSec->sectorsPerCluster < 65525)
{
discFileSystem = FS_FAT16;
}
else
{
discFileSystem = FS_FAT32;
}
if (discFileSystem != FS_FAT32)
{
discRootDirClus = FAT16_ROOT_DIR_CLUSTER;
}
else // Set up for the FAT32 way
{
discRootDirClus = bootSec->extBlock.fat32.rootClus;
// Check if FAT mirroring is enabled
if (!(bootSec->extBlock.fat32.extFlags & 0x80))
{
// Use the active FAT
discFAT = discFAT + ( discSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F));
}
}
return (true);
}
/*-----------------------------------------------------------------
getBootFileCluster
-----------------------------------------------------------------*/
u32 getBootFileCluster (const char* bootName)
{
DIR_ENT dir;
int firstSector = 0;
bool notFound = false;
bool found = false;
// int maxSectors;
u32 wrkDirCluster = discRootDirClus;
u32 wrkDirSector = 0;
int wrkDirOffset = 0;
int nameOffset;
dir.startCluster = CLUSTER_FREE; // default to no file found
dir.startClusterHigh = CLUSTER_FREE;
// Check if fat has been initialised
if (discBytePerSec == 0)
{
return (CLUSTER_FREE);
}
char *ptr = (char*)bootName;
while (*ptr != '.') ptr++;
int namelen = ptr - bootName;
// maxSectors = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? (discData - discRootDir) : discSecPerClus);
// Scan Dir for correct entry
firstSector = discRootDir;
CARD_ReadSector (firstSector + wrkDirSector, globalBuffer);
found = false;
notFound = false;
wrkDirOffset = -1; // Start at entry zero, Compensating for increment
while (!found && !notFound) {
wrkDirOffset++;
if (wrkDirOffset == BYTES_PER_SECTOR / sizeof (DIR_ENT))
{
wrkDirOffset = 0;
wrkDirSector++;
if ((wrkDirSector == discSecPerClus) && (wrkDirCluster != FAT16_ROOT_DIR_CLUSTER))
{
wrkDirSector = 0;
wrkDirCluster = FAT_NextCluster(wrkDirCluster);
if (wrkDirCluster == CLUSTER_EOF)
{
notFound = true;
}
firstSector = FAT_ClustToSect(wrkDirCluster);
}
else if ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER) && (wrkDirSector == (discData - discRootDir)))
{
notFound = true; // Got to end of root dir
}
CARD_ReadSector (firstSector + wrkDirSector, globalBuffer);
}
dir = ((DIR_ENT*) globalBuffer)[wrkDirOffset];
found = true;
if ((dir.attrib & ATTRIB_DIR) || (dir.attrib & ATTRIB_VOL))
{
found = false;
}
if(namelen<8 && dir.name[namelen]!=0x20) found = false;
for (nameOffset = 0; nameOffset < namelen && found; nameOffset++)
{
if (ucase(dir.name[nameOffset]) != bootName[nameOffset])
found = false;
}
for (nameOffset = 0; nameOffset < 3 && found; nameOffset++)
{
if (ucase(dir.ext[nameOffset]) != bootName[nameOffset+namelen+1])
found = false;
}
if (dir.name[0] == FILE_LAST)
{
notFound = true;
}
}
// If no file is found, return CLUSTER_FREE
if (notFound)
{
return CLUSTER_FREE;
}
return (dir.startCluster | (dir.startClusterHigh << 16));
}
/*-----------------------------------------------------------------
fileRead(buffer, cluster, startOffset, length)
-----------------------------------------------------------------*/
u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length)
{
int curByte;
int curSect;
int dataPos = 0;
int chunks;
int beginBytes;
if (cluster == CLUSTER_FREE || cluster == CLUSTER_EOF)
{
return 0;
}
// Follow cluster list until desired one is found
for (chunks = startOffset / discBytePerClus; chunks > 0; chunks--)
{
cluster = FAT_NextCluster (cluster);
}
// Calculate the sector and byte of the current position,
// and store them
curSect = (startOffset % discBytePerClus) / BYTES_PER_SECTOR;
curByte = startOffset % BYTES_PER_SECTOR;
// Load sector buffer for new position in file
CARD_ReadSector( curSect + FAT_ClustToSect(cluster), globalBuffer);
curSect++;
// Number of bytes needed to read to align with a sector
beginBytes = (BYTES_PER_SECTOR < length + curByte ? (BYTES_PER_SECTOR - curByte) : length);
// Read first part from buffer, to align with sector boundary
for (dataPos = 0 ; dataPos < beginBytes; dataPos++)
{
buffer[dataPos] = globalBuffer[curByte++];
}
// Read in all the 512 byte chunks of the file directly, saving time
for ( chunks = ((int)length - beginBytes) / BYTES_PER_SECTOR; chunks > 0;)
{
int sectorsToRead;
// Move to the next cluster if necessary
if (curSect >= discSecPerClus)
{
curSect = 0;
cluster = FAT_NextCluster (cluster);
}
// Calculate how many sectors to read (read a maximum of discSecPerClus at a time)
sectorsToRead = discSecPerClus - curSect;
if(chunks < sectorsToRead)
sectorsToRead = chunks;
// Read the sectors
CARD_ReadSectors(curSect + FAT_ClustToSect(cluster), sectorsToRead, buffer + dataPos);
chunks -= sectorsToRead;
curSect += sectorsToRead;
dataPos += BYTES_PER_SECTOR * sectorsToRead;
}
// Take care of any bytes left over before end of read
if (dataPos < length)
{
// Update the read buffer
curByte = 0;
if (curSect >= discSecPerClus)
{
curSect = 0;
cluster = FAT_NextCluster (cluster);
}
CARD_ReadSector( curSect + FAT_ClustToSect( cluster), globalBuffer);
// Read in last partial chunk
for (; dataPos < length; dataPos++)
{
buffer[dataPos] = globalBuffer[curByte];
curByte++;
}
}
return dataPos;
}

View 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 (void);
u32 getBootFileCluster (const char* bootName);
u32 fileRead (char* buffer, u32 cluster, u32 startOffset, u32 length);
u32 FAT_ClustToSect (u32 cluster);
#endif // FAT_H

View File

@ -0,0 +1,132 @@
/*-----------------------------------------------------------------
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 argStart
.global argSize
@---------------------------------------------------------------------------------
.align 4
.arm
@---------------------------------------------------------------------------------
_start:
@---------------------------------------------------------------------------------
b startUp
@ Used for passing arguments to the loaded app
argStart:
.word _end - _start
argSize:
.word 0x00000000
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
ldr r0, =0x02FFFDFB
mov r1, #42
strb r1, [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
mov r0, #0 @ int argc
mov r1, #0 @ char *argv[]
ldr r3, =main
bl _blx_r3_stub @ jump to user code
1: b 1b
@---------------------------------------------------------------------------------
_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
@---------------------------------------------------------------------------------

View File

@ -0,0 +1,315 @@
#include <nds.h>
#include "sdmmc.h"
static struct mmcdevice deviceSD;
/*mmcdevice *getMMCDevice(int drive) {
if(drive==0) return &deviceNAND;
return &deviceSD;
}
*/
//---------------------------------------------------------------------------------
int __attribute__((noinline)) geterror(struct mmcdevice *ctx) {
//---------------------------------------------------------------------------------
//if(ctx->error == 0x4) return -1;
//else return 0;
return (ctx->error << 29) >> 31;
}
//---------------------------------------------------------------------------------
void __attribute__((noinline)) 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 __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) {
//---------------------------------------------------------------------------------
int i;
bool getSDRESP = (cmd << 15) >> 31;
u16 flags = (cmd << 15) >> 31;
const bool readdata = cmd & 0x20000;
const bool writedata = cmd & 0x40000;
if (readdata || writedata)
flags |= TMIO_STAT0_DATAEND;
ctx->error = 0;
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
sdmmc_write16(REG_SDIRMASK0,0);
sdmmc_write16(REG_SDIRMASK1,0);
sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1,0);
#ifdef DATA32_SUPPORT
if (readdata)
sdmmc_mask16(REG_SDDATACTL32, 0x1000, 0x800);
if (writedata)
sdmmc_mask16(REG_SDDATACTL32, 0x800, 0x1000);
#else
sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
#endif
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
sdmmc_write16(REG_SDCMDARG1,args >> 16);
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
u32 size = ctx->size;
u16 *dataPtr = (u16*)ctx->data;
#ifdef DATA32_SUPPORT
u32 *dataPtr32 = (u32*)ctx->data;
#endif
bool useBuf = ( 0 != dataPtr );
#ifdef DATA32_SUPPORT
bool useBuf32 = (useBuf && (0 == (3 & ((u32)dataPtr))));
#endif
u16 status0 = 0;
while(true) {
u16 status1 = sdmmc_read16(REG_SDSTATUS1);
if (status1 & TMIO_STAT1_RXRDY) {
if (readdata && useBuf) {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
if (size > 0x1FF) {
#ifdef DATA32_SUPPORT
if (useBuf32) {
for(i = 0; i<0x200; i+=4)
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
} else {
#endif
for(i = 0; i<0x200; i+=2)
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
#ifdef DATA32_SUPPORT
}
#endif
size -= 0x200;
}
}
}
if (status1 & TMIO_STAT1_TXRQ) {
if (writedata && useBuf) {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
if (size > 0x1FF) {
#ifdef DATA32_SUPPORT
for (i = 0; i<0x200; i+=4)
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
#else
for (i = 0; i<0x200; i+=2)
sdmmc_write16(REG_SDFIFO,*dataPtr++);
#endif
size -= 0x200;
}
}
}
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() {
//---------------------------------------------------------------------------------
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 + 0xd8) & 0xFFDD) | 2;
#ifdef DATA32_SUPPORT
*(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFFu;
*(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDFu;
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 512;
#else
*(vu16*)(SDMMC_BASE + REG_SDDATACTL32) &= 0xFFFDu;
*(vu16*)(SDMMC_BASE + REG_SDDATACTL) &= 0xFFDDu;
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN32) = 0;
#endif
*(vu16*)(SDMMC_BASE + REG_SDBLKCOUNT32) = 1; //SDBLKCOUNT32
*(vu16*)(SDMMC_BASE + REG_SDRESET) &= 0xFFFEu; //SDRESET
*(vu16*)(SDMMC_BASE + REG_SDRESET) |= 1u; //SDRESET
*(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; //SDPORTSEL
#ifdef DATA32_SUPPORT
*(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x20;
*(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EE;
#else
*(vu16*)(SDMMC_BASE + REG_SDCLKCTL) = 0x40; //Nintendo sets this to 0x20
*(vu16*)(SDMMC_BASE + REG_SDOPT) = 0x40EB; //Nintendo sets this to 0x40EE
#endif
*(vu16*)(SDMMC_BASE + REG_SDPORTSEL) &= 0xFFFCu; ////SDPORTSEL
*(vu16*)(SDMMC_BASE + REG_SDBLKLEN) = 512; //SDBLKLEN
*(vu16*)(SDMMC_BASE + REG_SDSTOP) = 0; //SDSTOP
setTarget(&deviceSD);
}
//---------------------------------------------------------------------------------
static u32 calcSDSize(u8* csd, int type) {
//---------------------------------------------------------------------------------
u32 result = 0;
if (type == -1) type = csd[14] >> 6;
switch (type) {
case 0:
{
u32 block_len = csd[9] & 0xf;
block_len = 1 << block_len;
u32 mult = (csd[4] >> 7) | ((csd[5] & 3) << 1);
mult = 1 << (mult + 2);
result = csd[8] & 3;
result = (result << 8) | csd[7];
result = (result << 2) | (csd[6] >> 6);
result = (result + 1) * mult * block_len / 512;
}
break;
case 1:
result = csd[7] & 0x3f;
result = (result << 8) | csd[6];
result = (result << 8) | csd[5];
result = (result + 1) * 1024;
break;
}
return result;
}
//---------------------------------------------------------------------------------
int sdmmc_sdcard_init() {
//---------------------------------------------------------------------------------
setTarget(&deviceSD);
swiDelay(0xF000);
sdmmc_send_command(&deviceSD,0,0);
sdmmc_send_command(&deviceSD,0x10408,0x1AA);
//u32 temp = (deviceSD.ret[0] == 0x1AA) << 0x1E;
u32 temp = (deviceSD.error & 0x1) << 0x1E;
//int count = 0;
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);
//do
//{
// sdmmc_send_command(&deviceSD,0x10437,deviceSD.initarg << 0x10);
// sdmmc_send_command(&deviceSD,0x10769,0x00FF8000 | temp);
//
//}
//while(!(deviceSD.ret[0] & 0x80000000));
if(!((deviceSD.ret[0] >> 30) & 1) || !temp)
temp2 = 0;
deviceSD.isSDHC = temp2;
//deviceSD.isSDHC = (deviceSD.ret[0] & 0x40000000);
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.total_size = calcSDSize((u8*)&deviceSD.ret[0],-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;
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 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out) {
if (deviceSD.isSDHC == 0)
sector_no <<= 9;
setTarget(&deviceSD);
sdmmc_write16(REG_SDSTOP,0x100);
#ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
deviceSD.data = out;
deviceSD.size = numsectors << 9;
sdmmc_send_command(&deviceSD,0x33C12,sector_no);
return geterror(&deviceSD);
}

View File

@ -0,0 +1,175 @@
#ifndef __SDMMC_H__
#define __SDMMC_H__
#include <nds/ndstypes.h>
#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
//Comes from TWLSDK mongoose.tef DWARF info
#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;
void sdmmc_controller_init();
void sdmmc_initirq();
int sdmmc_cardinserted();
int sdmmc_sdcard_init();
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out);
int sdmmc_sdcard_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

View File

@ -0,0 +1,142 @@
#pragma once
#include <nds.h>
#define NDSHEADER ((tNDSHeader *)0x02FFFE00)
#define TWLNDSHEADER ((tTWLNDSHeader *)0x02FFE000)
#define BOOTFLAG *((vu8*)0x02FFFDFB)
#define BOOTLDR_NDS 0x02300000
#define BOOTLDR_NDSHEADER ((tNDSHeader *)BOOTLDR_NDS)
#define BOOTLDR_TWLNDSHEADER ((tTWLNDSHeader *)BOOTLDR_NDS)
typedef struct sTWLNDSHeader {
char gameTitle[12]; //!< 12 characters for the game title.
char gameCode[4]; //!< 4 characters for the game code.
char makercode[2]; //!< identifies the (commercial) developer.
u8 unitCode; //!< identifies the required hardware.
u8 deviceType; //!< type of device in the game card
u8 deviceSize; //!< capacity of the device (1 << n Mbit)
u8 reserved1[9];
u8 romversion; //!< version of the ROM.
u8 flags; //!< bit 2: auto-boot flag.
u32 arm9romOffset; //!< offset of the arm9 binary in the nds file.
u32 arm9executeAddress; //!< adress that should be executed after the binary has been copied.
u32 arm9destination; //!< destination address to where the arm9 binary should be copied.
u32 arm9binarySize; //!< size of the arm9 binary.
u32 arm7romOffset; //!< offset of the arm7 binary in the nds file.
u32 arm7executeAddress; //!< adress that should be executed after the binary has been copied.
u32 arm7destination; //!< destination address to where the arm7 binary should be copied.
u32 arm7binarySize; //!< size of the arm7 binary.
u32 filenameOffset; //!< File Name Table (FNT) offset.
u32 filenameSize; //!< File Name Table (FNT) size.
u32 fatOffset; //!< File Allocation Table (FAT) offset.
u32 fatSize; //!< File Allocation Table (FAT) size.
u32 arm9overlaySource; //!< File arm9 overlay offset.
u32 arm9overlaySize; //!< File arm9 overlay size.
u32 arm7overlaySource; //!< File arm7 overlay offset.
u32 arm7overlaySize; //!< File arm7 overlay size.
u32 cardControl13; //!< Port 40001A4h setting for normal commands (used in modes 1 and 3)
u32 cardControlBF; //!< Port 40001A4h setting for KEY1 commands (used in mode 2)
u32 bannerOffset; //!< offset to the banner with icon and titles etc.
u16 secureCRC16; //!< Secure Area Checksum, CRC-16.
u16 readTimeout; //!< Secure Area Loading Timeout.
u32 unknownRAM1; //!< ARM9 Auto Load List RAM Address (?)
u32 unknownRAM2; //!< ARM7 Auto Load List RAM Address (?)
u32 bfPrime1; //!< Secure Area Disable part 1.
u32 bfPrime2; //!< Secure Area Disable part 2.
u32 romSize; //!< total size of the ROM.
u32 headerSize; //!< ROM header size.
u32 zeros88[14];
u8 gbaLogo[156]; //!< Nintendo logo needed for booting the game.
u16 logoCRC16; //!< Nintendo Logo Checksum, CRC-16.
u16 headerCRC16; //!< header checksum, CRC-16.
u32 debugRomSource; //!< debug ROM offset.
u32 debugRomSize; //!< debug size.
u32 debugRomDestination; //!< debug RAM destination.
u32 offset_0x16C; //reserved?
u8 debug_reserved[0x10];
u8 config_settings[52];
u32 access_control;//0x1b4
u32 scfg_ext_mask;
u32 reserved_1bc;
u32 arm9iromOffset;
u32 arm9ireserved;
u32 arm9idestination;
u32 arm9ibinarySize;
u32 arm7iromOffset;
u32 arm7ititleparams;
u32 arm7idestination;
u32 arm7ibinarySize;
u32 digest_ntr_offset;
u32 digest_ntr_size;
u32 digest_twl_offset;
u32 digest_twl_size;
u32 digest_sector_hashtable_offset;
u32 digest_sector_hashtable_size;
u32 digest_block_hashtable_offset;
u32 digest_block_hashtable_size;
u32 digest_sector_size;
u32 digest_block_sectorcount;
u8 reserved_208[24];
u32 modcrypt1_offset;
u32 modcrypt1_size;
u32 modcrypt2_offset;
u32 modcrypt2_size;
u64 titleid;
u32 publicsav_size;
u32 privatesav_size;
u8 reserved_238[192];
u8 arm9_sec_hmac[20];//sha1 hmac /w encrypted secure area
u8 arm7_hmac[20];
u8 digest_master_hmac[20];
u8 banner_hmac[20];
u8 arm9i_hmac[20];
u8 arm7i_hmac[20];
u8 reserved_378[40];
u8 arm9_unsec_hmac[20];//without secure area
u8 reserved_3b4[2636];
u8 reserved_debugargs[0x180];
u8 signature[0x80];
} __attribute__ ((__packed__)) tTWLNDSHeader;
typedef unsigned int size_t;
void* memset(void* buffer, int val, size_t len);
void* memcpy(void* a, const void* b, size_t len);
void* memcpy16(void* a, const void* b, size_t len);
void memset_addrs(void* start, void* end);
void memcpy_addrs(void* start, void* end, void* dst);
void memcpy16_addrs(void* start, void* end, void* dst);
void* memcpy_arm9(u32 *a, u32 *b, size_t len);
void* memset_arm9(u32 *buffer, int val, size_t len);
void memset_arm7(u32 *buffer, int val, size_t len);
void memcpy_arm7(u32 *a, u32 *b, size_t len);
void memcpy8_arm7(u8 *a, u8 *b, size_t len);
void memset_addrs_arm7(u32 start, u32 end);
void memset8_arm7(u8 *buffer, int val, size_t len);

View File

@ -0,0 +1,126 @@
#include "common.h"
#include "ndsloader_bin.h"
static void resetArm9();
static void bootstrapArm7();
static void bootstrapArm7DSiSync();
static int sendipcmsg(u32 channel, u32 data);
static inline void debug_color(int r, int g, int b)
{
u16 clr = RGB15(r,g,b);
*(vu32*)0x05000000 = clr;
*(vu32*)0x05000400 = clr;
}
int main(void)
{
debug_color(31,15,0); // orange
resetArm9();
bootstrapArm7();
__builtin_unreachable();
}
void resetArm9()
{
int i, reg;
for(i=0; i<4; i++)
{
DMA_CR(i) = 0;//Reset DMA.
DMA_SRC(i) = 0;
DMA_DEST(i) = 0;
TIMER_CR(i) = 0;//Reset timers.
TIMER_DATA(i) = 0;
for(reg=0; reg<0x1c; reg+=4)*((u32*)(0x04004104 + ((i*0x1c)+reg))) = 0;//Reset NDMA.
}
VRAM_CR = 0;
VRAM_EFG_CR = 0;
VRAM_H_CR = 0;
VRAM_I_CR = 0;
REG_POWERCNT = 0x820f;
WRAM_CR = 0x03;
REG_EXMEMCNT = 0xE880;
}
int sendipcmsg(u32 chan, u32 data)
{
u32 dat = (chan & 0x1f) | (data<<6);
if(REG_IPC_FIFO_CR & (IPC_FIFO_SEND_FULL | IPC_FIFO_ERROR))return -1;
REG_IPC_FIFO_TX = dat;
return 0;
}
void bootstrapArm7()
{
REG_IME = 0;
REG_IE = 0;
REG_IF = ~0;
BOOTFLAG = 0;
*((vu32*)0x02FFFE04) = (u32)0xE59FF018;
*((vu32*)0x02FFFE24) = (u32)0x02FFFE04;
NDSHEADER->arm7executeAddress = 0x06000000;
while(sendipcmsg(12, 0x10<<8)<0);
debug_color(31,31,0); // yellow
bootstrapArm7DSiSync();
while(IPC_GetSync()!=1);
debug_color(31,0,31); // magenta
VRAM_C_CR = VRAM_ENABLE | VRAM_C_LCD;
memcpy16(VRAM_C, ndsloader_bin, ndsloader_bin_size);
VRAM_C_CR = VRAM_ENABLE | VRAM_C_ARM7_0x06000000;
debug_color(0,15,0); // dark green
IPC_SendSync(1);
while(IPC_GetSync()==1);
IPC_SendSync(0);
debug_color(0,31,0); // green
while (BOOTFLAG != 42);
debug_color(15,31,15); // bright green
swiSoftReset();
__builtin_unreachable();
}
void bootstrapArm7DSiSync()
{
vu16 *sync = (vu16*)0x02fffc24;
vu16 temp;
sync[2] = 4;
temp = sync[1];
while (sync[1]==temp);
sync[0]++;
sync[2] = 3; //When this is 3, Arm7 TWL SDK bootstub skips 7i bin loading, otherwise when 2 it loads the 7i bin.
temp = sync[1];
while (sync[1]==temp);
sync[0]++;
}
void* memcpy16(void* a, const void* b, size_t len)
{
vu16 *bufa = (vu16*)a;
vu16 *bufb = (vu16*)b;
while(len>0)
{
*bufa = *bufb;
bufa++;
bufb++;
len-=2;
}
return a;
}

View File

@ -0,0 +1,56 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
ELF loader: system startup
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//Modified for nzonehtmlhaxx by yellowstar6.
//Stripped down by fincs.
.arm
.arch armv5te
.fpu softvfp
.section .init
.global _start
_start:
@ clear BSS
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
bss_loop:
@ check for the end
cmp r1, r2
beq done_bss
@ clear the word and move on
str r3, [r1]
add r1, r1, #4
b bss_loop
done_bss:
ldr r0, =0x0000FFFF
mcr p15, 0, r0, c5, c0, 0
mcr p15, 0, r0, c5, c0, 1
ldr r0, =0x33333333
mcr p15, 0, r0, c5, c0, 2
mcr p15, 0, r0, c5, c0, 3
@ take the plunge
bl main
1: b 1b @ Added by yellowstar6. This code should never be executed.

View File

@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------
Copyright (C) 2009
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
.text
.align 4
.arm
@---------------------------------------------------------------------------------
.global swiSoftReset
.type swiSoftReset STT_FUNC
@---------------------------------------------------------------------------------
swiSoftReset:
@---------------------------------------------------------------------------------
.arch armv5te
.cpu arm946e-s
ldr r1, =0x00002078 @ disable TCM and protection unit
mcr p15, 0, r1, c1, c0
@ Disable cache
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ Instruction cache
mcr p15, 0, r0, c7, c6, 0 @ Data cache
@ Wait for write buffer to empty
mcr p15, 0, r0, c7, c10, 4
ldr r0,=0x2FFFE24
ldr r0,[r0]
bx r0
.pool

View File

@ -0,0 +1,102 @@
/*
elfloader - a Free Software replacement for the Nintendo/BroadOn IOS.
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
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, version 2.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*Modified for nzoneurlstacksmash.*/
OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
EXTERN(_start)
ENTRY(_start)
__base_addr = 0x02200000;
SECTIONS
{
. = __base_addr;
__code_start = .;
.init :
{
*(.init)
. = ALIGN(4);
}
.got :
{
__got_start = .;
*(.got.*)
*(.got)
. = ALIGN(4);
__got_end = . ;
}
.text :
{
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
}
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
}
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
. = ALIGN(4);
}
.bss :
{
__bss_start = . ;
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(32);
__bss_end = . ;
}
}
__end = __bss_end ;
__loader_size = __end - __code_start;
PROVIDE (__got_start = __got_start);
PROVIDE (__got_end = __got_end);
PROVIDE (__bss_start = __bss_start);
PROVIDE (__bss_end = __bss_end);