Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions arm7/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ include $(DEVKITARM)/ds_rules
TARGET := GodMode9i
BUILD := build
SOURCES := source
INCLUDES := include build
INCLUDES := include build ../arm9/source

#---------------------------------------------------------------------------------
# options for code generation
Expand Down Expand Up @@ -50,6 +50,8 @@ LIBS := -lnds7
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)

vpath encryption.c $(SHARED_ARM9_SOURCE)
vpath tonccpy.c $(SHARED_BOOTLOADER_SOURCE)

#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
Expand All @@ -59,8 +61,10 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------

export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export SHARED_ARM9_SOURCE := $(CURDIR)/../arm9/source
export SHARED_BOOTLOADER_SOURCE := $(CURDIR)/../bootloader/source

CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) encryption.c tonccpy.c
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))

Expand Down
151 changes: 151 additions & 0 deletions arm7/source/card_init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
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/>.

*/

#include "card_init.h"
#include "encryption.h"
#include "flashcard_init.h"
#include <stdlib.h>
#include <string.h>

static struct {
u32 iii, jjj, kkkkk, llll, mmm, nnn;
} key1data;

static void initKey1Command(u8* command) {
key1data.iii = rand() & 0xFFF;
key1data.jjj = rand() & 0xFFF;
key1data.kkkkk = rand() & 0xFFFFF;
key1data.llll = rand() & 0xFFFF;
key1data.mmm = rand() & 0xFFF;
key1data.nnn = rand() & 0xFFF;

command[7] = CARD_CMD_ACTIVATE_BF;
command[6] = key1data.iii >> 4;
command[5] = (key1data.iii << 4) | (key1data.jjj >> 8);
command[4] = key1data.jjj;
command[3] = key1data.kkkkk >> 16;
command[2] = key1data.kkkkk >> 8;
command[1] = key1data.kkkkk;
command[0] = rand();
}

static void encryptedCommand(u8 code, u8* command, u32 block) {
u32 iii = key1data.iii;
u32 jjj = key1data.jjj;
if (code != CARD_CMD_SECURE_READ)
block = key1data.llll;
if (code == CARD_CMD_ACTIVATE_SEC) {
iii = key1data.mmm;
jjj = key1data.nnn;
}

command[7] = code | (block >> 12);
command[6] = block >> 4;
command[5] = (block << 4) | (iii >> 8);
command[4] = iii;
command[3] = jjj >> 4;
command[2] = (jjj << 4) | (key1data.kkkkk >> 16);
command[1] = key1data.kkkkk >> 8;
command[0] = key1data.kkkkk;
crypt_64bit_up((u32*)command);
key1data.kkkkk++;
}

static void cardDelay(u16 timeout) {
TIMER_DATA(0) = 0 - ((timeout & 0x3FFF) + 3);
TIMER_CR(0) = TIMER_DIV_256 | TIMER_ENABLE;
while (TIMER_DATA(0) != 0xFFFF);
TIMER_CR(0) = 0;
TIMER_DATA(0) = 0;
}

u32 initFlashcardArm7(void) {
static const u8 seedBytes[] = {0xE8, 0x4D, 0x5A, 0xB1, 0x17, 0x8F, 0x99, 0xD5};
static u32 headerData[0x200 / sizeof(u32)];
tNDSHeader* header = (tNDSHeader*)headerData;
u8 command[8] __attribute__((aligned(4)));

cardReadHeader((u8*)headerData);
if (header->headerCRC16 != swiCRC16(0xFFFF, headerData, 0x15E))
return FLASHCARD_INIT_BAD_HEADER;

u32 chipId = cardReadID(CARD_CLK_SLOW);
while (REG_ROMCTRL & CARD_BUSY);
bool normalChip = (chipId & BIT(31)) != 0;
u32 gameCode;
memcpy(&gameCode, header->gameCode, sizeof(gameCode));
init_keycode(gameCode, 2, 8, NTR_CARD_KEY);

u32 key1Flags = CARD_ACTIVATE | CARD_nRESET |
(header->cardControl13 & (CARD_WR | CARD_CLK_SLOW)) |
((header->cardControlBF & (CARD_CLK_SLOW | CARD_DELAY1(0x1FFF))) +
((header->cardControlBF & CARD_DELAY2(0x3F)) >> 16));
if (!normalChip)
key1Flags |= CARD_SEC_LARGE;

initKey1Command(command);
cardPolledTransfer((header->cardControl13 & (CARD_WR | CARD_nRESET | CARD_CLK_SLOW)) |
CARD_ACTIVATE, NULL, 0, command);
encryptedCommand(CARD_CMD_ACTIVATE_SEC, command, 0);
if (normalChip) {
cardPolledTransfer(key1Flags, NULL, 0, command);
cardDelay(header->readTimeout);
}
cardPolledTransfer(key1Flags, NULL, 0, command);

REG_ROMCTRL = 0;
REG_CARD_1B0 = seedBytes[header->deviceType & 7] |
(key1data.nnn << 15) | (key1data.mmm << 27) | 0x6000;
REG_CARD_1B4 = 0x879B9B05;
REG_CARD_1B8 = key1data.mmm >> 5;
REG_CARD_1BA = 0x5C;
REG_ROMCTRL = CARD_nRESET | CARD_SEC_SEED | CARD_SEC_EN | CARD_SEC_DAT;
key1Flags |= CARD_SEC_EN | CARD_SEC_DAT;

encryptedCommand(CARD_CMD_SECURE_CHIPID, command, 0);
if (normalChip) {
cardPolledTransfer(key1Flags, NULL, 0, command);
cardDelay(header->readTimeout);
}
cardPolledTransfer(key1Flags | CARD_BLK_SIZE(7), NULL, 0, command);

u32 secureFlags = (header->cardControlBF &
(CARD_CLK_SLOW | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F))) |
CARD_ACTIVATE | CARD_nRESET | CARD_SEC_EN | CARD_SEC_DAT;
for (int block = 4; block < 8; block++) {
encryptedCommand(CARD_CMD_SECURE_READ, command, block);
if (normalChip) {
cardPolledTransfer(secureFlags, NULL, 0, command);
cardDelay(header->readTimeout);
for (int i = 0; i < 8; i++)
cardPolledTransfer(secureFlags | CARD_BLK_SIZE(1), NULL, 0, command);
} else {
cardPolledTransfer(secureFlags | CARD_BLK_SIZE(4) | CARD_SEC_LARGE,
NULL, 0, command);
}
}

encryptedCommand(CARD_CMD_DATA_MODE, command, 0);
if (normalChip) {
cardPolledTransfer(key1Flags, NULL, 0, command);
cardDelay(header->readTimeout);
}
cardPolledTransfer(key1Flags, NULL, 0, command);
return FLASHCARD_INIT_OK;
}
8 changes: 8 additions & 0 deletions arm7/source/card_init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef ARM7_CARD_INIT_H
#define ARM7_CARD_INIT_H

#include <nds.h>

u32 initFlashcardArm7(void);

#endif
10 changes: 9 additions & 1 deletion arm7/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <string.h>

#include "gba.h"
#include "card_init.h"
#include "flashcard_init.h"

#define SD_IRQ_STATUS (*(vu32*)0x400481C)

Expand Down Expand Up @@ -262,6 +264,13 @@ int main() {
}
resyncClock();

if (fifoCheckValue32(FLASHCARD_INIT_CHANNEL)) {
u32 command = fifoGetValue32(FLASHCARD_INIT_CHANNEL);
if (command == FLASHCARD_INIT_REQUEST) {
fifoSendValue32(FLASHCARD_INIT_CHANNEL, initFlashcardArm7());
}
}

// Send SD status
if(isDSiMode() || *(u16*)(0x4004700) != 0)
fifoSendValue32(FIFO_USER_04, SD_IRQ_STATUS);
Expand All @@ -282,4 +291,3 @@ int main() {
}
return 0;
}

36 changes: 34 additions & 2 deletions arm9/source/driveOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
#include "io_sc_common.h"
#include "exptools.h"
#include "read_card.h"
#include "flashcard_init.h"

static sNDSHeader nds;

static bool sdMountAttempted = false;

static bool slot1Enabled = true;

bool nandMounted = false;
Expand Down Expand Up @@ -166,6 +169,7 @@ void nandUnmount(void) {
}

bool sdMount(void) {
sdMountAttempted = true;
fatMountSimple("sd", __my_io_dsisd());
if (sdFound()) {
sdMountedDone = true;
Expand Down Expand Up @@ -421,6 +425,25 @@ TWL_CODE bool twl_flashcardMount(void) {
slot1Enabled = true;
}

// Follow HBMenu Deluxe's ARM7-first initialization order, without a later slot reset:
// https://github.com/ApacheThunder/ntr-hb-menu/blob/deluxe/arm7/source/main.c
// https://github.com/ApacheThunder/ntr-hb-menu/blob/deluxe/arm9/include/read_card.c
if (sdMountAttempted) {
sysSetCardOwner(BUS_OWNER_ARM7);
if (!fifoSendValue32(FLASHCARD_INIT_CHANNEL, FLASHCARD_INIT_REQUEST)) {
sysSetCardOwner(BUS_OWNER_ARM9);
printf("Failed to request ARM7 card initialization.\n");
return false;
}
fifoWaitValue32(FLASHCARD_INIT_CHANNEL);
u32 cardInitResult = fifoGetValue32(FLASHCARD_INIT_CHANNEL);
sysSetCardOwner(BUS_OWNER_ARM9);
if (cardInitResult != FLASHCARD_INIT_OK) {
printf("ARM7 card initialization failed: %lu\n", (unsigned long)cardInitResult);
return false;
}
}

nds.gameCode[0] = 0;
nds.gameTitle[0] = 0;
char gamename[13];
Expand Down Expand Up @@ -466,8 +489,17 @@ TWL_CODE bool twl_flashcardMount(void) {
fatMountSimple("fat", dldiGet());
}*/

if (doCardInit) {
cardInit((sNDSHeaderExt*)((u32*)0x02FFC000)); // Certain flashcarts require card init before DLDI will work.
if (doCardInit) { // Certain flashcarts require card init before DLDI will work.
sNDSHeaderExt* cardHeader = (sNDSHeaderExt*)((u32*)0x02FFC000);
if (sdMountAttempted) {
int result = cardInitWithoutSlotReset(cardHeader);
if (result != 0) {
printf("ARM9 card initialization failed: %d\n", result);
return false;
}
} else {
cardInit(cardHeader);
}
for (int i = 0; i < 30; i++) swiWaitForVBlank();
if (isDSPico) picoInit(false);
}
Expand Down
9 changes: 9 additions & 0 deletions arm9/source/flashcard_init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef FLASHCARD_INIT_H
#define FLASHCARD_INIT_H

#define FLASHCARD_INIT_CHANNEL FIFO_USER_03
#define FLASHCARD_INIT_REQUEST 0x54494E49 // 'INIT'
#define FLASHCARD_INIT_OK 0
#define FLASHCARD_INIT_BAD_HEADER 0x16

#endif
13 changes: 11 additions & 2 deletions arm9/source/read_card.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ void cardTwlBlowfishInit(sNDSHeaderExt* ndsHeader) {
}


int cardInit (sNDSHeaderExt* ndsHeader)
static int cardInitInternal (sNDSHeaderExt* ndsHeader, bool resetSlot)
{
u32 portFlagsKey1, portFlagsSecRead;
normalChip = false; // As defined by GBAtek, normal chip secure area and header are accessed in blocks of 0x200, other chip in blocks of 0x1000
Expand All @@ -351,7 +351,8 @@ int cardInit (sNDSHeaderExt* ndsHeader)
twlBlowfish = false;

sysSetCardOwner (BUS_OWNER_ARM9); // Allow arm9 to access NDS cart
cardDSiSlot1Reset();
if (resetSlot)
cardDSiSlot1Reset();

REG_ROMCTRL=0;
REG_AUXSPICNT=0;
Expand Down Expand Up @@ -520,6 +521,14 @@ int cardInit (sNDSHeaderExt* ndsHeader)
return ERR_NONE;
}

int cardInit (sNDSHeaderExt* ndsHeader) {
return cardInitInternal(ndsHeader, true);
}

int cardInitWithoutSlotReset (sNDSHeaderExt* ndsHeader) {
return cardInitInternal(ndsHeader, false);
}

u32 cardGetId() {
return iCardId;
}
Expand Down
1 change: 1 addition & 0 deletions arm9/source/read_card.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern u32 cardNandRomEnd;
extern u32 cardNandRwStart;

int cardInit (sNDSHeaderExt* ndsHeader);
int cardInitWithoutSlotReset (sNDSHeaderExt* ndsHeader);

void cardRead (u32 src, void* dest, bool nandSave);

Expand Down
Loading