Skip to content

Commit d9227c9

Browse files
committed
Add Slot-1 microSD access support (on DSi/3DS) for N-Card
1 parent e1bf1d1 commit d9227c9

File tree

3 files changed

+374
-14
lines changed

3 files changed

+374
-14
lines changed

settings/arm9/source/twlFlashcard.cpp

Lines changed: 190 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
#include "common/flashcard.h"
88
#include "common/bootstrappaths.h"
99
#include "common/inifile.h"
10+
#include "common/lzss.h"
1011
#include "common/systemdetails.h"
12+
#include "common/tonccpy.h"
1113
#include "read_card.h"
1214

1315
/*TWL_CODE bool UpdateCardInfo(char* gameid, char* gamename) {
14-
cardReadHeader((uint8*)&ndsCardHeader);
1516
memcpy(gameid, ndsCardHeader.gameCode, 4);
1617
gameid[4] = 0x00;
1718
memcpy(gamename, ndsCardHeader.gameTitle, 12);
@@ -23,6 +24,183 @@ TWL_CODE void ShowGameInfo(const char gameid[], const char gamename[]) {
2324
iprintf("Game id: %s\nName: %s", gameid, gamename);
2425
}*/
2526

27+
typedef signed int addr_t;
28+
typedef unsigned char data_t;
29+
30+
#define FIX_ALL 0x01
31+
#define FIX_GLUE 0x02
32+
#define FIX_GOT 0x04
33+
#define FIX_BSS 0x08
34+
35+
enum DldiOffsets {
36+
DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm"
37+
DO_magicToken = 0x00, // 0xBF8DA5ED
38+
DO_magicShortString = 0x04, // " Chishm"
39+
DO_version = 0x0C,
40+
DO_driverSize = 0x0D,
41+
DO_fixSections = 0x0E,
42+
DO_allocatedSpace = 0x0F,
43+
44+
DO_friendlyName = 0x10,
45+
46+
DO_text_start = 0x40, // Data start
47+
DO_data_end = 0x44, // Data end
48+
DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing
49+
DO_glue_end = 0x4C, // Interworking glue end
50+
DO_got_start = 0x50, // GOT start -- Needs address fixing
51+
DO_got_end = 0x54, // GOT end
52+
DO_bss_start = 0x58, // bss start -- Needs setting to zero
53+
DO_bss_end = 0x5C, // bss end
54+
55+
// IO_INTERFACE data
56+
DO_ioType = 0x60,
57+
DO_features = 0x64,
58+
DO_startup = 0x68,
59+
DO_isInserted = 0x6C,
60+
DO_readSectors = 0x70,
61+
DO_writeSectors = 0x74,
62+
DO_clearStatus = 0x78,
63+
DO_shutdown = 0x7C,
64+
DO_code = 0x80
65+
};
66+
67+
static addr_t readAddr (data_t *mem, addr_t offset) {
68+
return ((addr_t*)mem)[offset/sizeof(addr_t)];
69+
}
70+
71+
static void writeAddr (data_t *mem, addr_t offset, addr_t value) {
72+
((addr_t*)mem)[offset/sizeof(addr_t)] = value;
73+
}
74+
75+
TWL_CODE static void dldiRelocateBinary (data_t *binData, size_t dldiFileSize)
76+
{
77+
addr_t memOffset; // Offset of DLDI after the file is loaded into memory
78+
addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly
79+
addr_t ddmemOffset; // Original offset used in the DLDI file
80+
addr_t ddmemStart; // Start of range that offsets can be in the DLDI file
81+
addr_t ddmemEnd; // End of range that offsets can be in the DLDI file
82+
addr_t ddmemSize; // Size of range that offsets can be in the DLDI file
83+
84+
addr_t addrIter;
85+
86+
data_t *pDH = binData;
87+
data_t *pAH = (data_t*)(io_dldi_data);
88+
89+
// size_t dldiFileSize = 1 << pDH[DO_driverSize];
90+
91+
memOffset = readAddr (pAH, DO_text_start);
92+
if (memOffset == 0) {
93+
memOffset = readAddr (pAH, DO_startup) - DO_code;
94+
}
95+
ddmemOffset = readAddr (pDH, DO_text_start);
96+
relocationOffset = memOffset - ddmemOffset;
97+
98+
ddmemStart = readAddr (pDH, DO_text_start);
99+
ddmemSize = (1 << pDH[DO_driverSize]);
100+
ddmemEnd = ddmemStart + ddmemSize;
101+
102+
// Remember how much space is actually reserved
103+
pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
104+
// Copy the DLDI patch into the application
105+
tonccpy (pAH, pDH, dldiFileSize);
106+
107+
// Fix the section pointers in the header
108+
writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
109+
writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
110+
writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
111+
writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
112+
writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
113+
writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
114+
writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
115+
writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
116+
// Fix the function pointers in the header
117+
writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
118+
writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
119+
writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
120+
writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
121+
writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
122+
writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);
123+
124+
if (pDH[DO_fixSections] & FIX_ALL) {
125+
// Search through and fix pointers within the data section of the file
126+
for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
127+
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
128+
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
129+
}
130+
}
131+
}
132+
133+
if (pDH[DO_fixSections] & FIX_GLUE) {
134+
// Search through and fix pointers within the glue section of the file
135+
for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
136+
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
137+
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
138+
}
139+
}
140+
}
141+
142+
if (pDH[DO_fixSections] & FIX_GOT) {
143+
// Search through and fix pointers within the Global Offset Table section of the file
144+
for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
145+
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
146+
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
147+
}
148+
}
149+
}
150+
151+
if (pDH[DO_fixSections] & FIX_BSS) {
152+
// Initialise the BSS to 0
153+
toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
154+
}
155+
}
156+
157+
TWL_CODE void myDldiLoadFromFile (const char* filename) {
158+
extern bool extension(const std::string_view filename, const std::vector<std::string_view> extensions);
159+
160+
u32* dldiAddr = new u32[0x8000/sizeof(u32)];
161+
162+
FILE* file = fopen(filename, "rb");
163+
if (extension(filename, {".lz77"})) {
164+
fread((void*)0x02FF8004, 1, 0x3FFC, file);
165+
166+
*(u32*)0x02FF8000 = 0x53535A4C;
167+
LZ77_Decompress((u8*)0x02FF8004, (u8*)dldiAddr);
168+
} else {
169+
fread(dldiAddr, 1, 0x8000, file);
170+
}
171+
fclose(file);
172+
173+
// Check that it is a valid DLDI
174+
if (!dldiIsValid ((DLDI_INTERFACE*)dldiAddr)) {
175+
delete[] dldiAddr;
176+
return;
177+
}
178+
179+
DLDI_INTERFACE* device = (DLDI_INTERFACE*)dldiAddr;
180+
size_t dldiSize;
181+
182+
// Calculate actual size of DLDI
183+
// Although the file may only go to the dldiEnd, the BSS section can extend past that
184+
if (device->dldiEnd > device->bssEnd) {
185+
dldiSize = (char*)device->dldiEnd - (char*)device->dldiStart;
186+
} else {
187+
dldiSize = (char*)device->bssEnd - (char*)device->dldiStart;
188+
}
189+
dldiSize = (dldiSize + 0x03) & ~0x03; // Round up to nearest integer multiple
190+
191+
dldiRelocateBinary ((data_t*)dldiAddr, dldiSize);
192+
delete[] dldiAddr;
193+
}
194+
195+
TWL_CODE const DISC_INTERFACE *dldiGet(void) {
196+
if(io_dldi_data->ioInterface.features & FEATURE_SLOT_GBA)
197+
sysSetCartOwner(BUS_OWNER_ARM9);
198+
if(io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS)
199+
sysSetCardOwner(BUS_OWNER_ARM9);
200+
201+
return &io_dldi_data->ioInterface;
202+
}
203+
26204
TWL_CODE void twl_flashcardInit(void) {
27205
if (REG_SCFG_MC != 0x11 && !sys().arm7SCFGLocked()) {
28206
// Reset Slot-1 to allow reading title name and ID
@@ -31,23 +209,19 @@ TWL_CODE void twl_flashcardInit(void) {
31209
CIniFile settingsini( DSIMENUPP_INI );
32210

33211
if (settingsini.GetInt("SRLOADER", "SECONDARY_ACCESS", 0) == false) {
212+
disableSlot1();
34213
return;
35214
}
36215

37216
// Read title name and ID
38217
cardInit();
39218

40-
//char gamename[13];
41-
//char gameid[5];
219+
/*char gamename[13];
220+
char gameid[5];
42221
43-
/*fifoSendValue32(FIFO_USER_04, 1);
44-
for (int i = 0; i < 10; i++) {
45-
swiWaitForVBlank();
46-
}
47-
memcpy(&nds, (void*)0x02000000, sizeof(nds));*/
48-
//UpdateCardInfo(&gameid[0], &gamename[0]);
222+
UpdateCardInfo(&gameid[0], &gamename[0]);
49223
50-
/*consoleDemoInit();
224+
consoleDemoInit();
51225
iprintf("REG_SCFG_MC: %x\n", REG_SCFG_MC);
52226
ShowGameInfo(gameid, gamename);
53227
@@ -72,8 +246,11 @@ TWL_CODE void twl_flashcardInit(void) {
72246
fatMountSimple("fat", &io_dldi_data->ioInterface);
73247
} else*/ if (!memcmp(ndsCardHeader.gameTitle, "QMATETRIAL", 9) || !memcmp(ndsCardHeader.gameTitle, "R4DSULTRA", 9) // R4iDSN/R4 Ultra
74248
|| !memcmp(ndsCardHeader.gameCode, "ACEK", 4) || !memcmp(ndsCardHeader.gameCode, "YCEP", 4) || !memcmp(ndsCardHeader.gameCode, "AHZH", 4) || !memcmp(ndsCardHeader.gameCode, "CHPJ", 4) || !memcmp(ndsCardHeader.gameCode, "ADLP", 4)) { // Acekard 2(i)
75-
io_dldi_data = dldiLoadFromFile("nitro:/dldi/ak2.dldi");
76-
fatMountSimple("fat", &io_dldi_data->ioInterface);
249+
myDldiLoadFromFile("nitro:/dldi/ak2.dldi");
250+
fatMountSimple("fat", dldiGet());
251+
} else if (!memcmp(ndsCardHeader.gameCode, "DSGB", 4)) {
252+
myDldiLoadFromFile("nitro:/dldi/nrio.lz77");
253+
fatMountSimple("fat", dldiGet());
77254
} /*else if (!memcmp(ndsCardHeader.gameCode, "ALXX", 4)) {
78255
io_dldi_data = dldiLoadFromFile("nitro:/dldi/dstwo.dldi");
79256
fatMountSimple("fat", &io_dldi_data->ioInterface);
@@ -82,6 +259,7 @@ TWL_CODE void twl_flashcardInit(void) {
82259
fatMountSimple("fat", &io_dldi_data->ioInterface);
83260
} */
84261

262+
flashcardFoundReset();
85263
if (!flashcardFound()) {
86264
disableSlot1();
87265
}

settings/nitrofiles/dldi/nrio.lz77

12.2 KB
Binary file not shown.

0 commit comments

Comments
 (0)