mirror of
https://github.com/ApacheThunder/nds-bootloader.git
synced 2025-06-18 19:25:31 -04:00
Initial Commit
This commit is contained in:
parent
0371d04170
commit
bd9620f265
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*build
|
||||||
|
load.bin
|
||||||
|
load.elf
|
123
Makefile
Normal file
123
Makefile
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
|
||||||
|
endif
|
||||||
|
|
||||||
|
-include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := load
|
||||||
|
BUILD ?= build
|
||||||
|
SOURCES := source source/patches
|
||||||
|
INCLUDES := build
|
||||||
|
SPECS := specs
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -mthumb -mthumb-interwork
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -Os\
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||||
|
-ffast-math \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) $(EXTRA_CFLAGS) -DARM7
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH) $(EXTRA_CFLAGS) $(INCLUDE)
|
||||||
|
LDFLAGS = -nostartfiles -T $(TOPDIR)/load.ld -Wl,--no-warn-rwx-segments -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
arm9code/mpu_reset.s
Normal file
110
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
load.ld
Normal file
198
load.ld
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
|
||||||
|
vram : ORIGIN = 0x06000000, LENGTH = 128K
|
||||||
|
}
|
||||||
|
|
||||||
|
__vram_start = ORIGIN(vram);
|
||||||
|
__vram_top = ORIGIN(vram)+ LENGTH(vram);
|
||||||
|
__sp_irq = __vram_top - 0x60;
|
||||||
|
__sp_svc = __sp_irq - 0x100;
|
||||||
|
__sp_usr = __sp_svc - 0x100;
|
||||||
|
|
||||||
|
__irq_flags = __vram_top - 8;
|
||||||
|
__irq_vector = __vram_top - 4;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
__text_start = . ;
|
||||||
|
KEEP (*(.init))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.plt :
|
||||||
|
{
|
||||||
|
*(.plt)
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.text : /* ALIGN (4): */
|
||||||
|
{
|
||||||
|
|
||||||
|
*(.text*)
|
||||||
|
*(.stub)
|
||||||
|
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.gnu.linkonce.t*)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(.fini))
|
||||||
|
} >vram =0xff
|
||||||
|
|
||||||
|
__text_end = . ;
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
*all.rodata*(*)
|
||||||
|
*(.roda)
|
||||||
|
*(.rodata.*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >vram
|
||||||
|
__exidx_start = .;
|
||||||
|
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >vram
|
||||||
|
__exidx_end = .;
|
||||||
|
|
||||||
|
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||||
|
could instead move the label definition inside the section, but
|
||||||
|
the linker would then create the section even if it turns out to
|
||||||
|
be empty, which isn't pretty. */
|
||||||
|
. = ALIGN(32 / 8);
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
.preinit_array : { KEEP (*(.preinit_array)) } >vram = 0xff
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
.init_array : { KEEP (*(.init_array)) } >vram = 0xff
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
.fini_array : { KEEP (*(.fini_array)) } >vram = 0xff
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of the constructors, so
|
||||||
|
we make sure it is first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not actually link against
|
||||||
|
crtbegin.o; the linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it doesn't matter which
|
||||||
|
directory crtbegin.o is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.eh_frame :
|
||||||
|
{
|
||||||
|
KEEP (*(.eh_frame))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
.gcc_except_table :
|
||||||
|
{
|
||||||
|
*(.gcc_except_table)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram = 0xff
|
||||||
|
.jcr : { KEEP (*(.jcr)) } >vram = 0
|
||||||
|
.got : { *(.got.plt) *(.got) } >vram = 0
|
||||||
|
|
||||||
|
|
||||||
|
.vram ALIGN(4) :
|
||||||
|
{
|
||||||
|
__vram_start = ABSOLUTE(.) ;
|
||||||
|
*(.vram)
|
||||||
|
*vram.*(.text)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
__vram_end = ABSOLUTE(.) ;
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
|
||||||
|
.data ALIGN(4) : {
|
||||||
|
__data_start = ABSOLUTE(.);
|
||||||
|
*(.data)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
CONSTRUCTORS
|
||||||
|
. = ALIGN(4);
|
||||||
|
__data_end = ABSOLUTE(.) ;
|
||||||
|
} >vram = 0xff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.bss ALIGN(4) :
|
||||||
|
{
|
||||||
|
__bss_start = ABSOLUTE(.);
|
||||||
|
__bss_start__ = ABSOLUTE(.);
|
||||||
|
*(.dynbss)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >vram
|
||||||
|
|
||||||
|
__bss_end = . ;
|
||||||
|
__bss_end__ = . ;
|
||||||
|
|
||||||
|
_end = . ;
|
||||||
|
__end__ = . ;
|
||||||
|
PROVIDE (end = _end);
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
.stack 0x80000 : { _stack = .; *(.stack) }
|
||||||
|
/* These must appear regardless of . */
|
||||||
|
}
|
70
source/arm7clear.s
Normal file
70
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
|
||||||
|
|
94
source/arm9clear.arm.c
Normal file
94
source/arm9clear.arm.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#define ARM9
|
||||||
|
#undef ARM7
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <nds/dma.h>
|
||||||
|
#include <nds/system.h>
|
||||||
|
#include <nds/interrupts.h>
|
||||||
|
#include <nds/timers.h>
|
||||||
|
|
||||||
|
#include <nds/memory.h>
|
||||||
|
#include <nds/arm9/video.h>
|
||||||
|
#include <nds/arm9/input.h>
|
||||||
|
|
||||||
|
#include "boot.h"
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
resetMemory2_ARM9
|
||||||
|
Clears the ARM9's DMA channels and resets video memory
|
||||||
|
Written by Darkain.
|
||||||
|
Modified by Chishm:
|
||||||
|
* Changed MultiNDS specific stuff
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9 (void)
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
//clear out ARM9 DMA channels
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
DMA_CR(i) = 0;
|
||||||
|
DMA_SRC(i) = 0;
|
||||||
|
DMA_DEST(i) = 0;
|
||||||
|
TIMER_CR(i) = 0;
|
||||||
|
TIMER_DATA(i) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VRAM_CR = (VRAM_CR & 0xffff0000) | 0x00008080 ;
|
||||||
|
|
||||||
|
vu16 *mainregs = (vu16*)0x04000000;
|
||||||
|
vu16 *subregs = (vu16*)0x04001000;
|
||||||
|
|
||||||
|
for (i=0; i<43; i++) {
|
||||||
|
mainregs[i] = 0;
|
||||||
|
subregs[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_DISPSTAT = 0;
|
||||||
|
|
||||||
|
VRAM_A_CR = 0;
|
||||||
|
VRAM_B_CR = 0;
|
||||||
|
// Don't mess with the ARM7's VRAM
|
||||||
|
// VRAM_C_CR = 0;
|
||||||
|
VRAM_D_CR = 0;
|
||||||
|
VRAM_E_CR = 0;
|
||||||
|
VRAM_F_CR = 0;
|
||||||
|
VRAM_G_CR = 0;
|
||||||
|
VRAM_H_CR = 0;
|
||||||
|
VRAM_I_CR = 0;
|
||||||
|
REG_POWERCNT = 0x820F;
|
||||||
|
|
||||||
|
//set shared ram to ARM7
|
||||||
|
WRAM_CR = 0x03;
|
||||||
|
|
||||||
|
// Return to passme loop
|
||||||
|
*((vu32*)0x02FFFE04) = (u32)0xE59FF018; // ldr pc, 0x02FFFE24
|
||||||
|
*((vu32*)0x02FFFE24) = (u32)0x02FFFE04; // Set ARM9 Loop address
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
"\tbx %0\n"
|
||||||
|
: : "r" (0x02FFFE04)
|
||||||
|
);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
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
source/arm9mpu_reset.s
Normal file
6
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
source/bios.s
Normal file
13
source/bios.s
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.global swiDelay
|
||||||
|
.thumb_func
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swiDelay:
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
swi 0x03
|
||||||
|
bx lr
|
387
source/boot.c
Normal file
387
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
source/boot.h
Normal file
10
source/boot.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _BOOT_H_
|
||||||
|
#define _BOOT_H_
|
||||||
|
|
||||||
|
#define resetMemory2_ARM9_size 0x400
|
||||||
|
void __attribute__ ((long_call)) __attribute__((naked)) __attribute__((noreturn)) resetMemory2_ARM9();
|
||||||
|
#define startBinary_ARM9_size 0x100
|
||||||
|
void __attribute__ ((long_call)) __attribute__((noreturn)) __attribute__((naked)) startBinary_ARM9 ();
|
||||||
|
#define ARM9_START_FLAG (*(vu8*)0x02FFFDFB)
|
||||||
|
|
||||||
|
#endif // _BOOT_H_
|
45
source/card.h
Normal file
45
source/card.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
If you use this code, please give due credit and email me about your
|
||||||
|
project at chishm@hotmail.com
|
||||||
|
------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef CARD_H
|
||||||
|
#define CARD_H
|
||||||
|
|
||||||
|
#include "disc_io.h"
|
||||||
|
#include "io_dldi.h"
|
||||||
|
|
||||||
|
static inline bool CARD_StartUp (void) {
|
||||||
|
return _io_dldi.fn_startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool CARD_IsInserted (void) {
|
||||||
|
return _io_dldi.fn_isInserted();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool CARD_ReadSector (u32 sector, void *buffer) {
|
||||||
|
return _io_dldi.fn_readSectors(sector, 1, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool CARD_ReadSectors (u32 sector, int count, void *buffer) {
|
||||||
|
return _io_dldi.fn_readSectors(sector, count, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CARD_H
|
82
source/disc_io.h
Normal file
82
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
source/dldi_patcher.c
Normal file
223
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
source/dldi_patcher.h
Normal file
32
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
source/fat.c
Normal file
592
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
source/fat.h
Normal file
46
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
source/io_dldi.h
Normal file
44
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
source/io_dldi.s
Normal file
124
source/io_dldi.s
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*-----------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2005 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
If you use this code, please give due credit and email me about your
|
||||||
|
project at chishm@hotmail.com
|
||||||
|
------------------------------------------------------------------*/
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.align 4
|
||||||
|
.arm
|
||||||
|
.global _dldi_start
|
||||||
|
.global _io_dldi
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.equ FEATURE_MEDIUM_CANREAD, 0x00000001
|
||||||
|
.equ FEATURE_MEDIUM_CANWRITE, 0x00000002
|
||||||
|
.equ FEATURE_SLOT_GBA, 0x00000010
|
||||||
|
.equ FEATURE_SLOT_NDS, 0x00000020
|
||||||
|
|
||||||
|
|
||||||
|
_dldi_start:
|
||||||
|
#ifndef NO_DLDI
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ Driver patch file standard header -- 16 bytes
|
||||||
|
#ifdef STANDARD_DLDI
|
||||||
|
.word 0xBF8DA5ED @ Magic number to identify this region
|
||||||
|
#else
|
||||||
|
.word 0xBF8DA5EE @ Magic number to identify this region
|
||||||
|
#endif
|
||||||
|
.asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator)
|
||||||
|
.byte 0x01 @ Version number
|
||||||
|
.byte 0x0e @ 16KiB @ Log [base-2] of the size of this driver in bytes.
|
||||||
|
.byte 0x00 @ Sections to fix
|
||||||
|
.byte 0x0e @ 16KiB @ Log [base-2] of the allocated space in bytes.
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes
|
||||||
|
.align 4
|
||||||
|
.asciz "Loader (No interface)"
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ Offsets to important sections within the data -- 32 bytes
|
||||||
|
.align 6
|
||||||
|
.word _dldi_start @ data start
|
||||||
|
.word _dldi_end @ data end
|
||||||
|
.word 0x00000000 @ Interworking glue start -- Needs address fixing
|
||||||
|
.word 0x00000000 @ Interworking glue end
|
||||||
|
.word 0x00000000 @ GOT start -- Needs address fixing
|
||||||
|
.word 0x00000000 @ GOT end
|
||||||
|
.word 0x00000000 @ bss start -- Needs setting to zero
|
||||||
|
.word 0x00000000 @ bss end
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ IO_INTERFACE data -- 32 bytes
|
||||||
|
_io_dldi:
|
||||||
|
.ascii "DLDI" @ ioType
|
||||||
|
.word 0x00000000 @ Features
|
||||||
|
.word _DLDI_startup @
|
||||||
|
.word _DLDI_isInserted @
|
||||||
|
.word _DLDI_readSectors @ Function pointers to standard device driver functions
|
||||||
|
.word _DLDI_writeSectors @
|
||||||
|
.word _DLDI_clearStatus @
|
||||||
|
.word _DLDI_shutdown @
|
||||||
|
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_DLDI_startup:
|
||||||
|
_DLDI_isInserted:
|
||||||
|
_DLDI_readSectors:
|
||||||
|
_DLDI_writeSectors:
|
||||||
|
_DLDI_clearStatus:
|
||||||
|
_DLDI_shutdown:
|
||||||
|
mov r0, #0x00 @ Return false for every function
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
.align
|
||||||
|
.pool
|
||||||
|
|
||||||
|
.space (_dldi_start + 16384) - . @ Fill to 16KiB
|
||||||
|
|
||||||
|
_dldi_end:
|
||||||
|
.end
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
#else
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
|
@ IO_INTERFACE data -- 32 bytes
|
||||||
|
_io_dldi:
|
||||||
|
.ascii "DLDI" @ ioType
|
||||||
|
.word 0x00000000 @ Features
|
||||||
|
.word _DLDI_startup @
|
||||||
|
.word _DLDI_isInserted @
|
||||||
|
.word _DLDI_readSectors @ Function pointers to standard device driver functions
|
||||||
|
.word _DLDI_writeSectors @
|
||||||
|
.word _DLDI_clearStatus @
|
||||||
|
.word _DLDI_shutdown @
|
||||||
|
|
||||||
|
_DLDI_startup:
|
||||||
|
_DLDI_isInserted:
|
||||||
|
_DLDI_readSectors:
|
||||||
|
_DLDI_writeSectors:
|
||||||
|
_DLDI_clearStatus:
|
||||||
|
_DLDI_shutdown:
|
||||||
|
mov r0, #0x00 @ Return false for every function
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
147
source/load_crt0.s
Normal file
147
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
source/sdmmc.c
Normal file
242
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
source/sdmmc.h
Normal file
194
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
|
Loading…
Reference in New Issue
Block a user