/* main.arm7.c By Michael Chisholm (Chishm) All resetMemory and startBinary functions are based on the MultiNDS loader by Darkain. Original source available at: http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp License: NitroHax -- Cheat tool for the Nintendo DS Copyright (C) 2008 Michael "Chishm" Chisholm This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef ARM7 # define ARM7 #endif #include #include #include #include #include #include #include // #include // #include // #include // #include #ifndef NULL #define NULL 0 #endif #include "common.h" #include "read_card.h" /*------------------------------------------------------------------------- External functions --------------------------------------------------------------------------*/ extern void arm7_clearmem (void* loc, size_t len); extern void arm7_reset (void); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Important things #define NDS_HEAD 0x027FFE00 tNDSHeader* ndsHeader = (tNDSHeader*)NDS_HEAD; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Used for debugging purposes /* Disabled for now. Re-enable to debug problems static void errorOutput (u32 code) { // Set the error code, then set our state to "error" arm9_errorCode = code; ipcSendState(ARM7_ERR); // Stop while(1); } */ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Firmware stuff #define FW_READ 0x03 void arm7_readFirmware (uint32 address, uint8 * buffer, uint32 size) { uint32 index; // Read command while (REG_SPICNT & SPI_BUSY); REG_SPICNT = SPI_ENABLE | SPI_CONTINUOUS | SPI_DEVICE_NVRAM; REG_SPIDATA = FW_READ; while (REG_SPICNT & SPI_BUSY); // Set the address REG_SPIDATA = (address>>16) & 0xFF; while (REG_SPICNT & SPI_BUSY); REG_SPIDATA = (address>>8) & 0xFF; while (REG_SPICNT & SPI_BUSY); REG_SPIDATA = (address) & 0xFF; while (REG_SPICNT & SPI_BUSY); for (index = 0; index < size; index++) { REG_SPIDATA = 0; while (REG_SPICNT & SPI_BUSY); buffer[index] = REG_SPIDATA & 0xFF; } REG_SPICNT = 0; } /*------------------------------------------------------------------------- arm7_resetMemory 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 arm7_resetMemory (void) { int i; u8 settings1, settings2; REG_IME = 0; for (i=0; i<16; i++) { SCHANNEL_CR(i) = 0; SCHANNEL_TIMER(i) = 0; SCHANNEL_SOURCE(i) = 0; SCHANNEL_LENGTH(i) = 0; } REG_SOUNDCNT = 0; // Clear out ARM7 DMA channels and timers for (i=0; i<4; i++) { DMA_CR(i) = 0; DMA_SRC(i) = 0; DMA_DEST(i) = 0; TIMER_CR(i) = 0; TIMER_DATA(i) = 0; } // Clear out FIFO REG_IPC_SYNC = 0; REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR; REG_IPC_FIFO_CR = 0; // clear IWRAM - 037F:8000 to 0380:FFFF, total 96KiB arm7_clearmem ((void*)0x037F8000, 96*1024); // clear most of EXRAM - except after 0x023FD800, which has the ARM9 code arm7_clearmem ((void*)0x02000000, 0x003FD800); // clear last part of EXRAM, skipping the ARM9's section arm7_clearmem ((void*)0x023FE000, 0x2000); REG_IE = 0; REG_IF = ~0; (*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version (*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version REG_POWERCNT = 1; //turn off power to stuffs // Reload DS Firmware settings arm7_readFirmware((u32)0x03FE70, &settings1, 0x1); arm7_readFirmware((u32)0x03FF70, &settings2, 0x1); if (settings1 > settings2) { arm7_readFirmware((u32)0x03FE00, (u8*)0x027FFC80, 0x70); arm7_readFirmware((u32)0x03FF00, (u8*)0x027FFD80, 0x70); } else { arm7_readFirmware((u32)0x03FF00, (u8*)0x027FFC80, 0x70); arm7_readFirmware((u32)0x03FE00, (u8*)0x027FFD80, 0x70); } // Load FW header arm7_readFirmware((u32)0x000000, (u8*)0x027FF830, 0x20); } int arm7_loadBinary (void) { u32 chipID; u32 errorCode; // Init card errorCode = cardInit(ndsHeader, &chipID); if (errorCode) { return errorCode; } // Set memory values expected by loaded NDS *((u32*)0x027ff800) = chipID; // CurrentCardID *((u32*)0x027ff804) = chipID; // Command10CardID *((u32*)0x027ffc00) = chipID; // 3rd chip ID *((u16*)0x027ff808) = ndsHeader->headerCRC16; // Header Checksum, CRC-16 of [000h-15Dh] *((u16*)0x027ff80a) = ndsHeader->secureCRC16; // Secure Area Checksum, CRC-16 of [ [20h]..7FFFh] *((u16*)0x027ffc40) = 0x1; // Booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr cardRead(ndsHeader->arm9romOffset, (u32*)ndsHeader->arm9destination, ndsHeader->arm9binarySize); cardRead(ndsHeader->arm7romOffset, (u32*)ndsHeader->arm7destination, ndsHeader->arm7binarySize); return ERR_NONE; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Main function void arm7_main (void) { int errorCode; // Synchronise start while (ipcRecvState() != ARM9_START); ipcSendState(ARM7_START); // Wait until ARM9 is ready while (ipcRecvState() != ARM9_READY); ipcSendState(ARM7_MEMCLR); // Get ARM7 to clear RAM arm7_resetMemory(); ipcSendState(ARM7_LOADBIN); // Load the NDS file errorCode = arm7_loadBinary(); if (errorCode) { // errorOutput(errorCode); } ipcSendState(ARM7_BOOTBIN); arm7_reset(); }