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.
223 lines
7.9 KiB
C
223 lines
7.9 KiB
C
/*-----------------------------------------------------------------
|
|
|
|
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
|
|
------------------------------------------------------------------*/
|
|
#ifndef NO_DLDI
|
|
#include <string.h>
|
|
#include <nds.h>
|
|
#include "dldi_patcher.h"
|
|
|
|
#define FIX_ALL 0x01
|
|
#define FIX_GLUE 0x02
|
|
#define FIX_GOT 0x04
|
|
#define FIX_BSS 0x08
|
|
|
|
enum DldiOffsets {
|
|
DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm"
|
|
DO_magicToken = 0x00, // 0xBF8DA5ED
|
|
DO_magicShortString = 0x04, // " Chishm"
|
|
DO_version = 0x0C,
|
|
DO_driverSize = 0x0D,
|
|
DO_fixSections = 0x0E,
|
|
DO_allocatedSpace = 0x0F,
|
|
|
|
DO_friendlyName = 0x10,
|
|
|
|
DO_text_start = 0x40, // Data start
|
|
DO_data_end = 0x44, // Data end
|
|
DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing
|
|
DO_glue_end = 0x4C, // Interworking glue end
|
|
DO_got_start = 0x50, // GOT start -- Needs address fixing
|
|
DO_got_end = 0x54, // GOT end
|
|
DO_bss_start = 0x58, // bss start -- Needs setting to zero
|
|
DO_bss_end = 0x5C, // bss end
|
|
|
|
// IO_INTERFACE data
|
|
DO_ioType = 0x60,
|
|
DO_features = 0x64,
|
|
DO_startup = 0x68,
|
|
DO_isInserted = 0x6C,
|
|
DO_readSectors = 0x70,
|
|
DO_writeSectors = 0x74,
|
|
DO_clearStatus = 0x78,
|
|
DO_shutdown = 0x7C,
|
|
DO_code = 0x80
|
|
};
|
|
|
|
static addr_t readAddr (data_t *mem, addr_t offset) {
|
|
return ((addr_t*)mem)[offset/sizeof(addr_t)];
|
|
}
|
|
|
|
static void writeAddr (data_t *mem, addr_t offset, addr_t value) {
|
|
((addr_t*)mem)[offset/sizeof(addr_t)] = value;
|
|
}
|
|
|
|
|
|
static addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) {
|
|
const int* dataChunk = (const int*) data;
|
|
int searchChunk = ((const int*)search)[0];
|
|
addr_t i;
|
|
addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int));
|
|
|
|
for ( i = 0; i < dataChunkEnd; i++) {
|
|
if (dataChunk[i] == searchChunk) {
|
|
if ((i*sizeof(int) + searchLen) > dataLen) {
|
|
return -1;
|
|
}
|
|
if (memcmp (&data[i*sizeof(int)], search, searchLen) == 0) {
|
|
return i*sizeof(int);
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Strings are stored with bit 0x20 flipped (case inverted) to prevent accidental DLDI patching of them
|
|
#define DLDI_MAGIC_LEN 12
|
|
#define DLDI_MAGIC_MANGLE_VALUE 0x20
|
|
static const data_t dldiMagicStringMangled[DLDI_MAGIC_LEN] = "\xCD\x85\xAD\x9F\0cHISHM"; // Normal DLDI file
|
|
|
|
// Demangle the magic string by XORing every byte with 0x20, except the NULL terminator
|
|
static void demangleMagicString(data_t *dest, const data_t *src) {
|
|
int i;
|
|
|
|
memcpy(dest, src, DLDI_MAGIC_LEN);
|
|
for (i = 0; i < DLDI_MAGIC_LEN - 1; ++i) {
|
|
dest[i] ^= DLDI_MAGIC_MANGLE_VALUE;
|
|
}
|
|
}
|
|
|
|
#define DEVICE_TYPE_DLDI 0x49444C44
|
|
|
|
extern data_t _dldi_start[];
|
|
|
|
bool dldiPatchBinary (data_t *binData, u32 binSize) {
|
|
|
|
addr_t memOffset; // Offset of DLDI after the file is loaded into memory
|
|
addr_t patchOffset; // Position of patch destination in the file
|
|
addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly
|
|
addr_t ddmemOffset; // Original offset used in the DLDI file
|
|
addr_t ddmemStart; // Start of range that offsets can be in the DLDI file
|
|
addr_t ddmemEnd; // End of range that offsets can be in the DLDI file
|
|
addr_t ddmemSize; // Size of range that offsets can be in the DLDI file
|
|
addr_t addrIter;
|
|
|
|
data_t *pDH;
|
|
data_t *pAH;
|
|
|
|
data_t dldiMagicString[DLDI_MAGIC_LEN];
|
|
size_t dldiFileSize = 0;
|
|
|
|
// Find the DLDI reserved space in the file
|
|
demangleMagicString(dldiMagicString, dldiMagicStringMangled);
|
|
patchOffset = quickFind (binData, dldiMagicString, binSize, sizeof(dldiMagicString));
|
|
|
|
if (patchOffset < 0) {
|
|
// does not have a DLDI section
|
|
return false;
|
|
}
|
|
|
|
pDH = _dldi_start;
|
|
pAH = &(binData[patchOffset]);
|
|
|
|
if (*((u32*)(pDH + DO_ioType)) == DEVICE_TYPE_DLDI) {
|
|
// No DLDI patch
|
|
return false;
|
|
}
|
|
|
|
if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) {
|
|
// Not enough space for patch
|
|
return false;
|
|
}
|
|
|
|
dldiFileSize = 1 << pDH[DO_driverSize];
|
|
|
|
memOffset = readAddr (pAH, DO_text_start);
|
|
if (memOffset == 0) {
|
|
memOffset = readAddr (pAH, DO_startup) - DO_code;
|
|
}
|
|
ddmemOffset = readAddr (pDH, DO_text_start);
|
|
relocationOffset = memOffset - ddmemOffset;
|
|
|
|
ddmemStart = readAddr (pDH, DO_text_start);
|
|
ddmemSize = (1 << pDH[DO_driverSize]);
|
|
ddmemEnd = ddmemStart + ddmemSize;
|
|
|
|
// Remember how much space is actually reserved
|
|
pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
|
|
// Copy the DLDI patch into the application
|
|
memcpy (pAH, pDH, dldiFileSize);
|
|
|
|
// Fix the section pointers in the header
|
|
writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
|
|
writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
|
|
writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
|
|
writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
|
|
writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
|
|
writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
|
|
writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
|
|
writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
|
|
// Fix the function pointers in the header
|
|
writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
|
|
writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
|
|
writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
|
|
writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
|
|
writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
|
|
writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);
|
|
|
|
// Put the correct DLDI magic string back into the DLDI header
|
|
memcpy (pAH, dldiMagicString, sizeof (dldiMagicString));
|
|
|
|
if (pDH[DO_fixSections] & FIX_ALL) {
|
|
// Search through and fix pointers within the data section of the file
|
|
for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
|
|
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
|
|
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pDH[DO_fixSections] & FIX_GLUE) {
|
|
// Search through and fix pointers within the glue section of the file
|
|
for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
|
|
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
|
|
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pDH[DO_fixSections] & FIX_GOT) {
|
|
// Search through and fix pointers within the Global Offset Table section of the file
|
|
for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
|
|
if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
|
|
writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pDH[DO_fixSections] & FIX_BSS) {
|
|
// Initialise the BSS to 0
|
|
memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif |