mirror of
https://github.com/ApacheThunder/NTR_Launcher.git
synced 2025-06-18 19:15:40 -04:00

* Stage2 launcher UI added. This is a heavily modified HBMenu with ability to launch carts! This menu can be used to boot a bootloader NDS file for flascharts that the direct cart launcher fails to boot. * New audio files added for new menu. * HBMenu UI loaded by default if booted with no cart inserted. * INI file folder now located in NTR_Launcher folder instead. A default ini file from NitroFS (if mount of nitrofs succeeds) will be copied to SD if one is not present. * Stage2 launchers are expected to be in NTR Launcehr folder though you can navigate to any folder you want in the UI so stage2 launchers aren't the only thing this can be used for. You can also use this as a means of booting homebrew off SD in NTR mode.
607 lines
20 KiB
C
Executable File
607 lines
20 KiB
C
Executable File
/*
|
|
main.arm7.c
|
|
|
|
By Michael Chisholm (Chishm)
|
|
|
|
All resetMemory and startBinary functions are based
|
|
on the MultiNDS loader by Darkain.
|
|
Original source available at:
|
|
http://cvs.sourceforge.net/viewcvs.py/ndslib/ndslib/examples/loader/boot/main.cpp
|
|
|
|
License:
|
|
NitroHax -- Cheat tool for the Nintendo DS
|
|
Copyright (C) 2008 Michael "Chishm" Chisholm
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef ARM7
|
|
# define ARM7
|
|
#endif
|
|
#include <nds/ndstypes.h>
|
|
#include <nds/system.h>
|
|
#include <nds/interrupts.h>
|
|
#include <nds/timers.h>
|
|
#include <nds/dma.h>
|
|
#include <nds/arm7/audio.h>
|
|
#include <nds/arm7/codec.h>
|
|
#include <nds/memory.h>
|
|
#include <nds/ipc.h>
|
|
#include <string.h>
|
|
|
|
#ifndef NULL
|
|
#define NULL 0
|
|
#endif
|
|
|
|
#include "common.h"
|
|
#include "read_card.h"
|
|
#include "tonccpy.h"
|
|
/*-------------------------------------------------------------------------
|
|
External functions
|
|
--------------------------------------------------------------------------*/
|
|
extern void arm7_clearmem (void* loc, size_t len);
|
|
extern void arm7_reset (void);
|
|
|
|
static bool useTwlCfg = false;
|
|
static int twlCfgLang = 0;
|
|
// static bool useShortInit = false;
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Important things
|
|
#define NDS_HEADER 0x027FFE00
|
|
#define NDS_HEADER_POKEMON 0x027FF000
|
|
#define TWL_HEADER 0x027FE000
|
|
#define TMP_HEADER 0x027FC000
|
|
tNDSHeader* ndsHeader;
|
|
tNDSHeader* tmpHeader;
|
|
|
|
#define REG_GPIO_WIFI *(vu16*)0x4004C04
|
|
|
|
static u32 chipID;
|
|
|
|
static tNDSHeader* loadHeader(tDSiHeader* twlHeaderTemp) {
|
|
tNDSHeader* ntrHeader = (tNDSHeader*)NDS_HEADER;
|
|
*ntrHeader = twlHeaderTemp->ndshdr;
|
|
if (ntrHeader->unitCode > 0) {
|
|
tDSiHeader* dsiHeader = (tDSiHeader*)TWL_HEADER; // __DSiHeader
|
|
*dsiHeader = *twlHeaderTemp;
|
|
}
|
|
return ntrHeader;
|
|
}
|
|
|
|
static void NDSTouchscreenMode(void) {
|
|
|
|
bool specialSetting = false;
|
|
u8 volLevel;
|
|
|
|
static const char list[][4] = {
|
|
"ABX", // NTR-ABXE Bomberman Land Touch!
|
|
"YO9", // NTR-YO9J Bokura no TV Game Kentei - Pikotto! Udedameshi
|
|
"ALH", // NTR-ALHE Flushed Away
|
|
"ACC", // NTR-ACCE Cooking Mama
|
|
"YCQ", // NTR-YCQE Cooking Mama 2 - Dinner with Friends
|
|
"YYK", // NTR-YYKE Trauma Center - Under the Knife 2
|
|
"AZW", // NTR-AZWE WarioWare - Touched!
|
|
"AKA", // NTR-AKAE Rub Rabbits!, The
|
|
"AN9", // NTR-AN9E Little Mermaid - Ariel's Undersea Adventure, The
|
|
"AKE", // NTR-AKEJ Keroro Gunsou - Enshuu da Yo! Zenin Shuugou Part 2
|
|
"YFS", // NTR-YFSJ Frogman Show - DS Datte, Shouganaijanai, The
|
|
"YG8", // NTR-YG8E Yu-Gi-Oh! World Championship 2008
|
|
"AY7", // NTR-AY7E Yu-Gi-Oh! World Championship 2007
|
|
"YON", // NTR-YONJ Minna no DS Seminar - Kantan Ongakuryoku
|
|
"A5H", // NTR-A5HE Interactive Storybook DS - Series 2
|
|
"A5I", // NTR-A5IE Interactive Storybook DS - Series 3
|
|
"AMH", // NTR-AMHE Metroid Prime Hunters
|
|
"A3T", // NTR-A3TE Tak - The Great Juju Challenge
|
|
"YBO", // NTR-YBOE Boogie
|
|
"ADA", // NTR-ADAE PKMN Diamond
|
|
"APA", // NTR-APAE PKMN Pearl
|
|
"CPU", // NTR-CPUE PKMN Platinum
|
|
"APY", // NTR-APYE Puyo Pop Fever
|
|
"AWH", // NTR-AWHE Bubble Bobble Double Shot
|
|
"AXB", // NTR-AXBJ Daigassou! Band Brothers DX
|
|
"A4U", // NTR-A4UJ Wi-Fi Taiou - Morita Shogi
|
|
"A8N", // NTR-A8NE Planet Puzzle League
|
|
"ABJ", // NTR-ABJE Harvest Moon DS - Island of Happiness
|
|
"ABN", // NTR-ABNE Bomberman Story DS
|
|
"ACL", // NTR-ACLE Custom Robo Arena
|
|
"ART", // NTR-ARTJ Shin Lucky Star Moe Drill - Tabidachi
|
|
"AVT", // NTR-AVTJ Kou Rate Ura Mahjong Retsuden Mukoubuchi - Goburei, Shuuryou desu ne
|
|
"AWY", // NTR-AWYJ Wi-Fi Taiou - Gensen Table Game DS
|
|
"AXJ", // NTR-AXJE Dungeon Explorer - Warriors of Ancient Arts
|
|
"AYK", // NTR-AYKJ Wi-Fi Taiou - Yakuman DS
|
|
"YB2", // NTR-YB2E Bomberman Land Touch! 2
|
|
"YB3", // NTR-YB3E Harvest Moon DS - Sunshine Islands
|
|
"YCH", // NTR-YCHJ Kousoku Card Battle - Card Hero
|
|
"YFE", // NTR-YFEE Fire Emblem - Shadow Dragon
|
|
"YGD", // NTR-YGDE Diary Girl
|
|
"YKR", // NTR-YKRJ Culdcept DS
|
|
"YRM", // NTR-YRME My Secret World by Imagine
|
|
"YW2", // NTR-YW2E Advance Wars - Days of Ruin
|
|
"AJU", // NTR-AJUJ Jump! Ultimate Stars
|
|
"ACZ", // NTR-ACZE Cars
|
|
"AHD", // NTR-AHDE Jam Sessions
|
|
"ANR", // NTR-ANRE Naruto - Saikyou Ninja Daikesshu 3
|
|
"YT3", // NTR-YT3E Tamagotchi Connection - Corner Shop 3
|
|
"AVI", // NTR-AVIJ Kodomo no Tame no Yomi Kikase - Ehon de Asobou 1-Kan
|
|
"AV2", // NTR-AV2J Kodomo no Tame no Yomi Kikase - Ehon de Asobou 2-Kan
|
|
"AV3", // NTR-AV3J Kodomo no Tame no Yomi Kikase - Ehon de Asobou 3-Kan
|
|
"AV4", // NTR-AV4J Kodomo no Tame no Yomi Kikase - Ehon de Asobou 4-Kan
|
|
"AV5", // NTR-AV5J Kodomo no Tame no Yomi Kikase - Ehon de Asobou 5-Kan
|
|
"AV6", // NTR-AV6J Kodomo no Tame no Yomi Kikase - Ehon de Asobou 6-Kan
|
|
"YNZ", // NTR-YNZE Petz - Dogz Fashion
|
|
};
|
|
|
|
for (unsigned int i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
|
|
if (memcmp(ndsHeader->gameCode, list[i], 3) == 0) {
|
|
// Found a match.
|
|
specialSetting = true; // Special setting (when found special gamecode)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (specialSetting) {
|
|
// special setting (when found special gamecode)
|
|
volLevel = 0xAC;
|
|
} else {
|
|
// normal setting (for any other gamecodes)
|
|
volLevel = 0xA7;
|
|
}
|
|
|
|
|
|
// Touchscreen
|
|
cdcReadReg (0x63, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x3A, 0x00);
|
|
cdcReadReg (CDC_CONTROL, 0x51);
|
|
cdcReadReg (CDC_TOUCHCNT, 0x02);
|
|
cdcReadReg (CDC_CONTROL, 0x3F);
|
|
cdcReadReg (CDC_SOUND, 0x28);
|
|
cdcReadReg (CDC_SOUND, 0x2A);
|
|
cdcReadReg (CDC_SOUND, 0x2E);
|
|
cdcWriteReg(CDC_CONTROL, 0x52, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x40, 0x0C);
|
|
cdcWriteReg(CDC_SOUND, 0x24, 0xFF);
|
|
cdcWriteReg(CDC_SOUND, 0x25, 0xFF);
|
|
cdcWriteReg(CDC_SOUND, 0x26, 0x7F);
|
|
cdcWriteReg(CDC_SOUND, 0x27, 0x7F);
|
|
cdcWriteReg(CDC_SOUND, 0x28, 0x4A);
|
|
cdcWriteReg(CDC_SOUND, 0x29, 0x4A);
|
|
cdcWriteReg(CDC_SOUND, 0x2A, 0x10);
|
|
cdcWriteReg(CDC_SOUND, 0x2B, 0x10);
|
|
cdcWriteReg(CDC_CONTROL, 0x51, 0x00);
|
|
cdcReadReg (CDC_TOUCHCNT, 0x02);
|
|
cdcWriteReg(CDC_TOUCHCNT, 0x02, 0x98);
|
|
cdcWriteReg(CDC_SOUND, 0x23, 0x00);
|
|
cdcWriteReg(CDC_SOUND, 0x1F, 0x14);
|
|
cdcWriteReg(CDC_SOUND, 0x20, 0x14);
|
|
cdcWriteReg(CDC_CONTROL, 0x3F, 0x00);
|
|
cdcReadReg (CDC_CONTROL, 0x0B);
|
|
cdcWriteReg(CDC_CONTROL, 0x05, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x0B, 0x01);
|
|
cdcWriteReg(CDC_CONTROL, 0x0C, 0x02);
|
|
cdcWriteReg(CDC_CONTROL, 0x12, 0x01);
|
|
cdcWriteReg(CDC_CONTROL, 0x13, 0x02);
|
|
cdcWriteReg(CDC_SOUND, 0x2E, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x3A, 0x60);
|
|
cdcWriteReg(CDC_CONTROL, 0x01, 0x01);
|
|
cdcWriteReg(CDC_CONTROL, 0x39, 0x66);
|
|
cdcReadReg (CDC_SOUND, 0x20);
|
|
cdcWriteReg(CDC_SOUND, 0x20, 0x10);
|
|
cdcWriteReg(CDC_CONTROL, 0x04, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x12, 0x81);
|
|
cdcWriteReg(CDC_CONTROL, 0x13, 0x82);
|
|
cdcWriteReg(CDC_CONTROL, 0x51, 0x82);
|
|
cdcWriteReg(CDC_CONTROL, 0x51, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x04, 0x03);
|
|
cdcWriteReg(CDC_CONTROL, 0x05, 0xA1);
|
|
cdcWriteReg(CDC_CONTROL, 0x06, 0x15);
|
|
cdcWriteReg(CDC_CONTROL, 0x0B, 0x87);
|
|
cdcWriteReg(CDC_CONTROL, 0x0C, 0x83);
|
|
cdcWriteReg(CDC_CONTROL, 0x12, 0x87);
|
|
cdcWriteReg(CDC_CONTROL, 0x13, 0x83);
|
|
cdcReadReg (CDC_TOUCHCNT, 0x10);
|
|
cdcWriteReg(CDC_TOUCHCNT, 0x10, 0x08);
|
|
cdcWriteReg(0x04, 0x08, 0x7F);
|
|
cdcWriteReg(0x04, 0x09, 0xE1);
|
|
cdcWriteReg(0x04, 0x0A, 0x80);
|
|
cdcWriteReg(0x04, 0x0B, 0x1F);
|
|
cdcWriteReg(0x04, 0x0C, 0x7F);
|
|
cdcWriteReg(0x04, 0x0D, 0xC1);
|
|
cdcWriteReg(CDC_CONTROL, 0x41, 0x08);
|
|
cdcWriteReg(CDC_CONTROL, 0x42, 0x08);
|
|
cdcWriteReg(CDC_CONTROL, 0x3A, 0x00);
|
|
cdcWriteReg(0x04, 0x08, 0x7F);
|
|
cdcWriteReg(0x04, 0x09, 0xE1);
|
|
cdcWriteReg(0x04, 0x0A, 0x80);
|
|
cdcWriteReg(0x04, 0x0B, 0x1F);
|
|
cdcWriteReg(0x04, 0x0C, 0x7F);
|
|
cdcWriteReg(0x04, 0x0D, 0xC1);
|
|
cdcWriteReg(CDC_SOUND, 0x2F, 0x2B);
|
|
cdcWriteReg(CDC_SOUND, 0x30, 0x40);
|
|
cdcWriteReg(CDC_SOUND, 0x31, 0x40);
|
|
cdcWriteReg(CDC_SOUND, 0x32, 0x60);
|
|
cdcReadReg (CDC_CONTROL, 0x74);
|
|
cdcWriteReg(CDC_CONTROL, 0x74, 0x02);
|
|
cdcReadReg (CDC_CONTROL, 0x74);
|
|
cdcWriteReg(CDC_CONTROL, 0x74, 0x10);
|
|
cdcReadReg (CDC_CONTROL, 0x74);
|
|
cdcWriteReg(CDC_CONTROL, 0x74, 0x40);
|
|
cdcWriteReg(CDC_SOUND, 0x21, 0x20);
|
|
cdcWriteReg(CDC_SOUND, 0x22, 0xF0);
|
|
cdcReadReg (CDC_CONTROL, 0x51);
|
|
cdcReadReg (CDC_CONTROL, 0x3F);
|
|
cdcWriteReg(CDC_CONTROL, 0x3F, 0xD4);
|
|
cdcWriteReg(CDC_SOUND, 0x23, 0x44);
|
|
cdcWriteReg(CDC_SOUND, 0x1F, 0xD4);
|
|
cdcWriteReg(CDC_SOUND, 0x28, 0x4E);
|
|
cdcWriteReg(CDC_SOUND, 0x29, 0x4E);
|
|
cdcWriteReg(CDC_SOUND, 0x24, 0x9E);
|
|
cdcWriteReg(CDC_SOUND, 0x25, 0x9E);
|
|
cdcWriteReg(CDC_SOUND, 0x20, 0xD4);
|
|
cdcWriteReg(CDC_SOUND, 0x2A, 0x14);
|
|
cdcWriteReg(CDC_SOUND, 0x2B, 0x14);
|
|
cdcWriteReg(CDC_SOUND, 0x26, 0xA7);
|
|
cdcWriteReg(CDC_SOUND, 0x27, 0xA7);
|
|
cdcWriteReg(CDC_CONTROL, 0x40, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x3A, 0x60);
|
|
cdcWriteReg(CDC_SOUND, 0x26, volLevel);
|
|
cdcWriteReg(CDC_SOUND, 0x27, volLevel);
|
|
cdcWriteReg(CDC_SOUND, 0x2E, 0x03);
|
|
cdcWriteReg(CDC_TOUCHCNT, 0x03, 0x00);
|
|
cdcWriteReg(CDC_SOUND, 0x21, 0x20);
|
|
cdcWriteReg(CDC_SOUND, 0x22, 0xF0);
|
|
cdcReadReg (CDC_SOUND, 0x22);
|
|
cdcWriteReg(CDC_SOUND, 0x22, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x52, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x51, 0x00);
|
|
|
|
// Set remaining values
|
|
cdcWriteReg(CDC_CONTROL, 0x03, 0x44);
|
|
cdcWriteReg(CDC_CONTROL, 0x0D, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x0E, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x0F, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x10, 0x08);
|
|
cdcWriteReg(CDC_CONTROL, 0x14, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x15, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x16, 0x04);
|
|
cdcWriteReg(CDC_CONTROL, 0x1A, 0x01);
|
|
cdcWriteReg(CDC_CONTROL, 0x1E, 0x01);
|
|
cdcWriteReg(CDC_CONTROL, 0x24, 0x80);
|
|
cdcWriteReg(CDC_CONTROL, 0x33, 0x34);
|
|
cdcWriteReg(CDC_CONTROL, 0x34, 0x32);
|
|
cdcWriteReg(CDC_CONTROL, 0x35, 0x12);
|
|
cdcWriteReg(CDC_CONTROL, 0x36, 0x03);
|
|
cdcWriteReg(CDC_CONTROL, 0x37, 0x02);
|
|
cdcWriteReg(CDC_CONTROL, 0x38, 0x03);
|
|
cdcWriteReg(CDC_CONTROL, 0x3C, 0x19);
|
|
cdcWriteReg(CDC_CONTROL, 0x3D, 0x05);
|
|
cdcWriteReg(CDC_CONTROL, 0x44, 0x0F);
|
|
cdcWriteReg(CDC_CONTROL, 0x45, 0x38);
|
|
cdcWriteReg(CDC_CONTROL, 0x49, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x4A, 0x00);
|
|
cdcWriteReg(CDC_CONTROL, 0x4B, 0xEE);
|
|
cdcWriteReg(CDC_CONTROL, 0x4C, 0x10);
|
|
cdcWriteReg(CDC_CONTROL, 0x4D, 0xD8);
|
|
cdcWriteReg(CDC_CONTROL, 0x4E, 0x7E);
|
|
cdcWriteReg(CDC_CONTROL, 0x4F, 0xE3);
|
|
cdcWriteReg(CDC_CONTROL, 0x58, 0x7F);
|
|
cdcWriteReg(CDC_CONTROL, 0x74, 0xD2);
|
|
cdcWriteReg(CDC_CONTROL, 0x75, 0x2C);
|
|
cdcWriteReg(CDC_SOUND, 0x22, 0x70);
|
|
cdcWriteReg(CDC_SOUND, 0x2C, 0x20);
|
|
|
|
// Finish up!
|
|
cdcReadReg (CDC_TOUCHCNT, 0x02);
|
|
cdcWriteReg(CDC_TOUCHCNT, 0x02, 0x98);
|
|
cdcWriteReg(0xFF, 0x05, 0x00); //writeTSC(0x00, 0xFF);
|
|
|
|
// Power management
|
|
writePowerManagement(PM_READ_REGISTER, 0x00); //*(unsigned char*)0x40001C2 = 0x80, 0x00; // read PWR[0] ;<-- also part of TSC !
|
|
writePowerManagement(PM_CONTROL_REG, 0x0D); //*(unsigned char*)0x40001C2 = 0x00, 0x0D; // PWR[0]=0Dh ;<-- also part of TSC !
|
|
}
|
|
|
|
const char* getRomTid(const tNDSHeader* ndsHeader) {
|
|
static char romTid[5];
|
|
strncpy(romTid, ndsHeader->gameCode, 4);
|
|
romTid[4] = '\0';
|
|
return romTid;
|
|
}
|
|
|
|
static void errorOutput (u32 code, bool isError) {
|
|
arm9_errorCode = code;
|
|
if (isError) {
|
|
ipcSendState(ARM7_ERR);
|
|
while(1); // Stop
|
|
}
|
|
}
|
|
|
|
static void arm7_readFirmware(tNDSHeader* ndsHeader) {
|
|
PERSONAL_DATA slot1;
|
|
PERSONAL_DATA slot2;
|
|
|
|
short slot1count, slot2count; //u8
|
|
short slot1CRC, slot2CRC;
|
|
|
|
u32 userSettingsBase;
|
|
|
|
// Get settings location
|
|
readFirmware(0x20, &userSettingsBase, 2);
|
|
|
|
u32 slot1Address = userSettingsBase * 8;
|
|
u32 slot2Address = userSettingsBase * 8 + 0x100;
|
|
|
|
// Reload DS Firmware settings
|
|
readFirmware(slot1Address, &slot1, sizeof(PERSONAL_DATA)); //readFirmware(slot1Address, personalData, 0x70);
|
|
readFirmware(slot2Address, &slot2, sizeof(PERSONAL_DATA)); //readFirmware(slot2Address, personalData, 0x70);
|
|
readFirmware(slot1Address + 0x70, &slot1count, 2); //readFirmware(slot1Address + 0x70, &slot1count, 1);
|
|
readFirmware(slot2Address + 0x70, &slot2count, 2); //readFirmware(slot1Address + 0x70, &slot2count, 1);
|
|
readFirmware(slot1Address + 0x72, &slot1CRC, 2);
|
|
readFirmware(slot2Address + 0x72, &slot2CRC, 2);
|
|
|
|
// Default to slot 1 user settings
|
|
void *currentSettings = &slot1;
|
|
|
|
short calc1CRC = swiCRC16(0xFFFF, &slot1, sizeof(PERSONAL_DATA));
|
|
short calc2CRC = swiCRC16(0xFFFF, &slot2, sizeof(PERSONAL_DATA));
|
|
|
|
// Bail out if neither slot is valid
|
|
if (calc1CRC != slot1CRC && calc2CRC != slot2CRC) { return; }
|
|
|
|
// If both slots are valid pick the most recent
|
|
if (calc1CRC == slot1CRC && calc2CRC == slot2CRC) {
|
|
currentSettings = (slot2count == ((slot1count + 1) & 0x7f) ? &slot2 : &slot1); //if ((slot1count & 0x7F) == ((slot2count + 1) & 0x7F)) {
|
|
} else {
|
|
if (calc2CRC == slot2CRC) { currentSettings = &slot2; }
|
|
}
|
|
|
|
PERSONAL_DATA* personalData = (PERSONAL_DATA*)((u32)__NDSHeader - (u32)ndsHeader + (u32)PersonalData); //(u8*)((u32)ndsHeader - 0x180)
|
|
|
|
tonccpy(PersonalData, currentSettings, sizeof(PERSONAL_DATA));
|
|
|
|
if (useTwlCfg && (language == 0xFF)) { language = twlCfgLang; }
|
|
|
|
if (language >= 0 && language <= 7) {
|
|
// Change language
|
|
personalData->language = language; //*(u8*)((u32)ndsHeader - 0x11C) = language;
|
|
}
|
|
|
|
if (personalData->language != 6 && ndsHeader->reserved1[8] == 0x80) {
|
|
ndsHeader->reserved1[8] = 0; // Patch iQue game to be region-free
|
|
ndsHeader->headerCRC16 = swiCRC16(0xFFFF, ndsHeader, 0x15E); // Fix CRC
|
|
}
|
|
}
|
|
|
|
static void arm7_resetMemory (void) {
|
|
int i, reg;
|
|
|
|
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;
|
|
for(reg=0; reg<0x1c; reg+=4)*((u32*)(0x04004104 + ((i*0x1c)+reg))) = 0; //Reset NDMA.
|
|
}
|
|
|
|
// 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 0x022FD800, which has the ARM9 code
|
|
// Skip 0x0200000 region if fastBoot enabled. (cart header copy stored here)
|
|
/*if (useShortInit) {
|
|
arm7_clearmem ((void*)0x02000200, 0x002FD600);
|
|
} else {
|
|
arm7_clearmem ((void*)0x02000000, 0x002FD800);
|
|
}*/
|
|
arm7_clearmem ((void*)0x02000000, 0x002FD800);
|
|
// clear last part of EXRAM, skipping the ARM9's section
|
|
arm7_clearmem ((void*)0x023FE000, 0x2000);
|
|
|
|
// Clear tmp header region previously used by custom struct
|
|
arm7_clearmem ((void*)TMP_HEADER, 0x160);
|
|
|
|
REG_IE = 0;
|
|
REG_IF = ~0;
|
|
REG_AUXIE = 0;
|
|
REG_AUXIF = ~0;
|
|
|
|
(*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version
|
|
(*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version
|
|
}
|
|
|
|
static void setMemoryAddress(const tNDSHeader* ndsHeader) {
|
|
if (ndsHeader->unitCode > 0) {
|
|
copyLoop((u32*)0x027FFA80, (u32*)ndsHeader, 0x160); // Make a duplicate of DS header
|
|
|
|
*(u32*)(0x027FA680) = 0x02FD4D80;
|
|
*(u32*)(0x027FA684) = 0x00000000;
|
|
*(u32*)(0x027FA688) = 0x00001980;
|
|
|
|
*(u32*)(0x027FF00C) = 0x0000007F;
|
|
*(u32*)(0x027FF010) = 0x550E25B8;
|
|
*(u32*)(0x027FF014) = 0x02FF4000;
|
|
|
|
// Set region flag
|
|
if (strncmp(getRomTid(ndsHeader)+3, "J", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 0;
|
|
} else if (strncmp(getRomTid(ndsHeader)+3, "E", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 1;
|
|
} else if (strncmp(getRomTid(ndsHeader)+3, "P", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 2;
|
|
} else if (strncmp(getRomTid(ndsHeader)+3, "U", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 3;
|
|
} else if (strncmp(getRomTid(ndsHeader)+3, "C", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 4;
|
|
} else if (strncmp(getRomTid(ndsHeader)+3, "K", 1) == 0) {
|
|
*(u8*)(0x027FFD70) = 5;
|
|
}
|
|
}
|
|
|
|
// Set memory values expected by loaded NDS
|
|
// from NitroHax, thanks to Chism
|
|
*((u32*)0x027FF800) = chipID; // CurrentCardID
|
|
*((u32*)0x027FF804) = chipID; // Command10CardID
|
|
*((u16*)0x027FF808) = ndsHeader->headerCRC16; // Header Checksum, CRC-16 of [000h-15Dh]
|
|
*((u16*)0x027FF80A) = ndsHeader->secureCRC16; // Secure Area Checksum, CRC-16 of [ [20h]..7FFFh]
|
|
*((u16*)0x027FF850) = 0x5835;
|
|
// Copies of above
|
|
*((u32*)0x027FFC00) = chipID; // CurrentCardID
|
|
*((u32*)0x027FFC04) = chipID; // Command10CardID
|
|
*((u16*)0x027FFC08) = ndsHeader->headerCRC16; // Header Checksum, CRC-16 of [000h-15Dh]
|
|
*((u16*)0x027FFC0A) = ndsHeader->secureCRC16; // Secure Area Checksum, CRC-16 of [ [20h]..7FFFh]
|
|
*((u16*)0x027FFC10) = 0x5835;
|
|
*((u16*)0x027FFC40) = 0x01; // Boot Indicator -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr
|
|
}
|
|
|
|
static u32 arm7_loadBinary (void) {
|
|
u32 errorCode;
|
|
|
|
tDSiHeader* twlHeaderTemp = (tDSiHeader*)TMP_HEADER; // Use same region cheat engine goes. Cheat engine will replace this later when it's not needed.
|
|
|
|
// Init card
|
|
/*if (useShortInit) {
|
|
errorCode = cardInitShort((sNDSHeaderExt*)twlHeaderTemp, &chipID);
|
|
arm7_clearmem ((void*)0x02000200, 0x200); // clear temp header data
|
|
} else {
|
|
errorCode = cardInit((sNDSHeaderExt*)twlHeaderTemp, &chipID);
|
|
}*/
|
|
|
|
errorCode = cardInit((sNDSHeaderExt*)twlHeaderTemp, &chipID);
|
|
|
|
if (errorCode)return errorCode;
|
|
|
|
ndsHeader = loadHeader(twlHeaderTemp); // copy twlHeaderTemp to ndsHeader location
|
|
|
|
cardRead(ndsHeader->arm9romOffset, (u32*)ndsHeader->arm9destination, ndsHeader->arm9binarySize);
|
|
cardRead(ndsHeader->arm7romOffset, (u32*)ndsHeader->arm7destination, ndsHeader->arm7binarySize);
|
|
|
|
// Fix Pokemon games needing header data.
|
|
copyLoop((u32*)NDS_HEADER_POKEMON, (u32*)NDS_HEADER, 0x170);
|
|
|
|
char* romTid = (char*)NDS_HEADER_POKEMON+0xC;
|
|
if ( memcpy(romTid, "ADA", 3) == 0 // Diamond
|
|
|| memcmp(romTid, "APA", 3) == 0 // Pearl
|
|
|| memcmp(romTid, "CPU", 3) == 0 // Platinum
|
|
|| memcmp(romTid, "IPK", 3) == 0 // HG
|
|
|| memcmp(romTid, "IPG", 3) == 0 // SS
|
|
) {
|
|
// Make the Pokemon game code ADAJ.
|
|
const char gameCodePokemon[] = { 'A', 'D', 'A', 'J' };
|
|
memcpy((char*)NDS_HEADER_POKEMON+0xC, gameCodePokemon, 4);
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Main function
|
|
void arm7_main (void) {
|
|
|
|
u32 errorCode;
|
|
|
|
// Synchronise start
|
|
while (ipcRecvState() != ARM9_START);
|
|
ipcSendState(ARM7_START);
|
|
|
|
// Wait until ARM9 is ready
|
|
while (ipcRecvState() != ARM9_READY);
|
|
|
|
if (language != 0xFF)language = (int)launchData->language;
|
|
if (launchData->scfgUnlock > 0x00)scfgUnlock = true;
|
|
if (launchData->twlMode > 0x00)twlMode = true;
|
|
if (launchData->twlCLK > 0x00)twlCLK = true;
|
|
if (launchData->debugMode > 0x00)debugMode = true;
|
|
// if (launchData->fastBoot > 0x00)useShortInit = true;
|
|
|
|
|
|
if (twlMode) {
|
|
REG_MBK9=0x0300000F;
|
|
REG_MBK6=0x080037C0;
|
|
REG_MBK7=0x07C03740;
|
|
REG_MBK8=0x07403700;
|
|
} else {
|
|
REG_MBK9=0xFCFFFF0F;
|
|
REG_MBK6=0x09403900;
|
|
REG_MBK7=0x09803940;
|
|
REG_MBK8=0x09C03980;
|
|
}
|
|
|
|
errorOutput(ERR_STS_CLR_MEM, false);
|
|
|
|
ipcSendState(ARM7_MEMCLR);
|
|
|
|
// Get ARM7 to clear RAM
|
|
arm7_resetMemory();
|
|
|
|
tmpHeader = (tNDSHeader*)TMP_HEADER;
|
|
|
|
if (!twlMode)REG_SCFG_ROM = 0x703;
|
|
|
|
errorOutput(ERR_STS_LOAD_BIN, false);
|
|
|
|
ipcSendState(ARM7_LOADBIN);
|
|
|
|
// Load the NDS file
|
|
errorCode = arm7_loadBinary();
|
|
if (errorCode)errorOutput(errorCode, true);
|
|
|
|
errorOutput(ERR_STS_STARTBIN, false);
|
|
|
|
tonccpy((u32*)0x023FF000, (u32*)0x027FF000, 0x1000);
|
|
|
|
arm7_readFirmware(ndsHeader); // Header has to be loaded first
|
|
|
|
if (twlMode) {
|
|
REG_SCFG_EXT = 0x92FBFB06;
|
|
} else {
|
|
if (cdcReadReg(CDC_SOUND, 0x22) == 0xF0) {
|
|
// Switch touch mode to NTR
|
|
*(u16*)0x4004700 = 0x800F;
|
|
NDSTouchscreenMode();
|
|
*(u16*)0x4000500 = 0x807F;
|
|
}
|
|
REG_GPIO_WIFI |= BIT(8); // Old NDS-Wifi mode
|
|
REG_SCFG_EXT = 0x92A00000;
|
|
}
|
|
|
|
if (twlCLK) { REG_SCFG_CLK = 0x0187; } else { REG_SCFG_CLK = 0x0101; }
|
|
if (scfgUnlock) { REG_SCFG_EXT |= BIT(18); } else { REG_SCFG_EXT &= ~(1UL << 31); }
|
|
|
|
setMemoryAddress(ndsHeader);
|
|
|
|
ipcSendState(ARM7_BOOTBIN);
|
|
|
|
// Moved here to prevent interfering with arm9main's new console
|
|
REG_POWERCNT = 1; //turn off power to stuffs
|
|
|
|
arm7_reset();
|
|
}
|
|
|