mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-06-18 10:55:31 -04:00
315 lines
8.5 KiB
C
315 lines
8.5 KiB
C
/*-----------------------------------------------------------------
|
|
boot.c
|
|
|
|
BootLoader
|
|
Loads a file into memory and runs it
|
|
|
|
All resetMemory and startBinary functions are based
|
|
on the MultiNDS loader by Darkain.
|
|
Original source available at:
|
|
http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp
|
|
|
|
License:
|
|
Copyright (C) 2005 Michael "Chishm" Chisholm
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
If you use this code, please give due credit and email me about your
|
|
project at chishm@hotmail.com
|
|
|
|
Helpful information:
|
|
This code runs from VRAM bank C on ARM7
|
|
------------------------------------------------------------------*/
|
|
|
|
#include <nds/ndstypes.h>
|
|
#include <nds/dma.h>
|
|
#include <nds/system.h>
|
|
#include <nds/interrupts.h>
|
|
#include <nds/timers.h>
|
|
#define ARM9
|
|
#undef ARM7
|
|
#include <nds/memory.h>
|
|
#include <nds/arm9/video.h>
|
|
#include <nds/arm9/input.h>
|
|
#undef ARM9
|
|
#define ARM7
|
|
#include <nds/arm7/audio.h>
|
|
|
|
#include "fat.h"
|
|
#include "dldi_patcher.h"
|
|
#include "card.h"
|
|
#include "boot.h"
|
|
|
|
void arm7clearRAM();
|
|
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, void *out);
|
|
int sdmmc_sdcard_init();
|
|
void sdmmc_controller_init();
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Important things
|
|
#define TEMP_MEM 0x02FFE000
|
|
#define NDS_HEAD 0x02FFFE00
|
|
#define TEMP_ARM9_START_ADDRESS (*(vu32*)0x02FFFFF4)
|
|
|
|
|
|
const char* bootName = "BOOT.NDS";
|
|
|
|
extern unsigned long _start;
|
|
extern unsigned long storedFileCluster;
|
|
extern unsigned long initDisc;
|
|
extern unsigned long wantToPatchDLDI;
|
|
extern unsigned long argStart;
|
|
extern unsigned long argSize;
|
|
extern unsigned long dsiSD;
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Firmware stuff
|
|
|
|
#define FW_READ 0x03
|
|
|
|
void boot_readFirmware (uint32 address, uint8 * buffer, uint32 size) {
|
|
uint32 index;
|
|
|
|
// Read command
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM;
|
|
REG_SPIDATA = FW_READ;
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
|
|
// Set the address
|
|
REG_SPIDATA = (address>>16) & 0xFF;
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
REG_SPIDATA = (address>>8) & 0xFF;
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
REG_SPIDATA = (address) & 0xFF;
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
|
|
for (index = 0; index < size; index++) {
|
|
REG_SPIDATA = 0;
|
|
while (REG_SPICNT & SPI_BUSY);
|
|
buffer[index] = REG_SPIDATA & 0xFF;
|
|
}
|
|
REG_SPICNT = 0;
|
|
}
|
|
|
|
|
|
static inline void copyLoop (u32* dest, const u32* src, u32 size) {
|
|
size = (size +3) & ~3;
|
|
do {
|
|
*dest++ = *src++;
|
|
} while (size -= 4);
|
|
}
|
|
|
|
//#define resetCpu() __asm volatile("\tswi 0x000000\n");
|
|
|
|
/*-------------------------------------------------------------------------
|
|
passArgs_ARM7
|
|
Copies the command line arguments to the end of the ARM9 binary,
|
|
then sets a flag in memory for the loaded NDS to use
|
|
--------------------------------------------------------------------------*/
|
|
void passArgs_ARM7 (void) {
|
|
u32 ARM9_DST = *((u32*)(NDS_HEAD + 0x028));
|
|
u32 ARM9_LEN = *((u32*)(NDS_HEAD + 0x02C));
|
|
u32* argSrc;
|
|
u32* argDst;
|
|
|
|
if (!argStart || !argSize) return;
|
|
|
|
argSrc = (u32*)(argStart + (int)&_start);
|
|
|
|
argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned
|
|
|
|
copyLoop(argDst, argSrc, argSize);
|
|
|
|
__system_argv->argvMagic = ARGV_MAGIC;
|
|
__system_argv->commandLine = (char*)argDst;
|
|
__system_argv->length = argSize;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
resetMemory_ARM7
|
|
Clears all of the NDS's RAM that is visible to the ARM7
|
|
Written by Darkain.
|
|
Modified by Chishm:
|
|
* Added STMIA clear mem loop
|
|
--------------------------------------------------------------------------*/
|
|
void resetMemory_ARM7 (void)
|
|
{
|
|
int i;
|
|
u8 settings1, settings2;
|
|
u32 settingsOffset = 0;
|
|
|
|
REG_IME = 0;
|
|
|
|
for (i=0; i<16; i++) {
|
|
SCHANNEL_CR(i) = 0;
|
|
SCHANNEL_TIMER(i) = 0;
|
|
SCHANNEL_SOURCE(i) = 0;
|
|
SCHANNEL_LENGTH(i) = 0;
|
|
}
|
|
|
|
REG_SOUNDCNT = 0;
|
|
|
|
//clear out ARM7 DMA channels and timers
|
|
for (i=0; i<4; i++) {
|
|
DMA_CR(i) = 0;
|
|
DMA_SRC(i) = 0;
|
|
DMA_DEST(i) = 0;
|
|
TIMER_CR(i) = 0;
|
|
TIMER_DATA(i) = 0;
|
|
}
|
|
|
|
arm7clearRAM();
|
|
|
|
REG_IE = 0;
|
|
REG_IF = ~0;
|
|
(*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version
|
|
(*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version
|
|
REG_POWERCNT = 1; //turn off power to stuff
|
|
|
|
// Get settings location
|
|
boot_readFirmware((u32)0x00020, (u8*)&settingsOffset, 0x2);
|
|
settingsOffset *= 8;
|
|
|
|
// Reload DS Firmware settings
|
|
boot_readFirmware(settingsOffset + 0x070, &settings1, 0x1);
|
|
boot_readFirmware(settingsOffset + 0x170, &settings2, 0x1);
|
|
|
|
if ((settings1 & 0x7F) == ((settings2+1) & 0x7F)) {
|
|
boot_readFirmware(settingsOffset + 0x000, (u8*)0x02FFFC80, 0x70);
|
|
} else {
|
|
boot_readFirmware(settingsOffset + 0x100, (u8*)0x02FFFC80, 0x70);
|
|
}
|
|
}
|
|
|
|
|
|
void loadBinary_ARM7 (u32 fileCluster)
|
|
{
|
|
u32 ndsHeader[0x170>>2];
|
|
|
|
// read NDS header
|
|
fileRead ((char*)ndsHeader, fileCluster, 0, 0x170);
|
|
// read ARM9 info from NDS header
|
|
u32 ARM9_SRC = ndsHeader[0x020>>2];
|
|
char* ARM9_DST = (char*)ndsHeader[0x028>>2];
|
|
u32 ARM9_LEN = ndsHeader[0x02C>>2];
|
|
// read ARM7 info from NDS header
|
|
u32 ARM7_SRC = ndsHeader[0x030>>2];
|
|
char* ARM7_DST = (char*)ndsHeader[0x038>>2];
|
|
u32 ARM7_LEN = ndsHeader[0x03C>>2];
|
|
|
|
// Load binaries into memory
|
|
fileRead(ARM9_DST, fileCluster, ARM9_SRC, ARM9_LEN);
|
|
fileRead(ARM7_DST, fileCluster, ARM7_SRC, ARM7_LEN);
|
|
|
|
// first copy the header to its proper location, excluding
|
|
// the ARM9 start address, so as not to start it
|
|
TEMP_ARM9_START_ADDRESS = ndsHeader[0x024>>2]; // Store for later
|
|
ndsHeader[0x024>>2] = 0;
|
|
dmaCopyWords(3, (void*)ndsHeader, (void*)NDS_HEAD, 0x170);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
startBinary_ARM7
|
|
Jumps to the ARM7 NDS binary in sync with the display and ARM9
|
|
Written by Darkain.
|
|
Modified by Chishm:
|
|
* Removed MultiNDS specific stuff
|
|
--------------------------------------------------------------------------*/
|
|
void startBinary_ARM7 (void) {
|
|
REG_IME=0;
|
|
while(REG_VCOUNT!=191);
|
|
while(REG_VCOUNT==191);
|
|
// copy NDS ARM9 start address into the header, starting ARM9
|
|
*((vu32*)0x02FFFE24) = TEMP_ARM9_START_ADDRESS;
|
|
ARM9_START_FLAG = 1;
|
|
// Start ARM7
|
|
VoidFn arm7code = *(VoidFn*)(0x2FFFE34);
|
|
arm7code();
|
|
}
|
|
|
|
int sdmmc_sd_readsectors(u32 sector_no, u32 numsectors, void *out);
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Main function
|
|
bool sdmmc_inserted() {
|
|
return true;
|
|
}
|
|
|
|
bool sdmmc_startup() {
|
|
sdmmc_controller_init();
|
|
return sdmmc_sdcard_init() == 0;
|
|
}
|
|
|
|
bool sdmmc_readsectors(u32 sector_no, u32 numsectors, void *out) {
|
|
return sdmmc_sdcard_readsectors(sector_no, numsectors, out) == 0;
|
|
}
|
|
|
|
int main (void) {
|
|
if (dsiSD) {
|
|
_io_dldi.fn_readSectors = sdmmc_readsectors;
|
|
_io_dldi.fn_isInserted = sdmmc_inserted;
|
|
_io_dldi.fn_startup = sdmmc_startup;
|
|
}
|
|
|
|
u32 fileCluster = storedFileCluster;
|
|
// Init card
|
|
if(!FAT_InitFiles(initDisc))
|
|
{
|
|
return -1;
|
|
}
|
|
if ((fileCluster < CLUSTER_FIRST) || (fileCluster >= CLUSTER_EOF)) /* Invalid file cluster specified */
|
|
{
|
|
fileCluster = getBootFileCluster(bootName);
|
|
}
|
|
if (fileCluster == CLUSTER_FREE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// ARM9 clears its memory part 2
|
|
// copy ARM9 function to RAM, and make the ARM9 jump to it
|
|
copyLoop((void*)TEMP_MEM, (void*)resetMemory2_ARM9, resetMemory2_ARM9_size);
|
|
(*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function
|
|
// Wait until the ARM9 has completed its task
|
|
while ((*(vu32*)0x02FFFE24) == (u32)TEMP_MEM);
|
|
|
|
// Get ARM7 to clear RAM
|
|
resetMemory_ARM7();
|
|
|
|
// ARM9 enters a wait loop
|
|
// copy ARM9 function to RAM, and make the ARM9 jump to it
|
|
copyLoop((void*)TEMP_MEM, (void*)startBinary_ARM9, startBinary_ARM9_size);
|
|
(*(vu32*)0x02FFFE24) = (u32)TEMP_MEM; // Make ARM9 jump to the function
|
|
|
|
// Load the NDS file
|
|
loadBinary_ARM7(fileCluster);
|
|
|
|
// Patch with DLDI if desired
|
|
if (wantToPatchDLDI) {
|
|
dldiPatchBinary ((u8*)((u32*)NDS_HEAD)[0x0A], ((u32*)NDS_HEAD)[0x0B]);
|
|
}
|
|
|
|
// Pass command line arguments to loaded program
|
|
passArgs_ARM7();
|
|
|
|
startBinary_ARM7();
|
|
|
|
return 0;
|
|
}
|
|
|