diff --git a/booter_fc/arm9/source/nds_loader_arm9.c b/booter_fc/arm9/source/nds_loader_arm9.c index 6655a6fda9..cb0da2de9c 100644 --- a/booter_fc/arm9/source/nds_loader_arm9.c +++ b/booter_fc/arm9/source/nds_loader_arm9.c @@ -390,42 +390,7 @@ int runNdsFile (const char* filename, int argc, const char** argv) { runNds9i(filename); } - bool loadFromRam = (runNds9(filename) || (isDSiMode() && access("sd:/", F_OK) != 0)); + const bool loadFromRam = (runNds9(filename) || (isDSiMode() && access("sd:/", F_OK) != 0)); - bool havedsiSD = (argv[0][0]=='s' && argv[0][1]=='d'); - installBootStub(havedsiSD); - return runNds (load_bin, load_bin_size, st.st_ino, true, (memcmp(io_dldi_data->friendlyName, "Default", 7) != 0), loadFromRam, argc, argv); } - - -bool installBootStub(bool havedsiSD) { -#ifndef _NO_BOOTSTUB_ - extern char *fake_heap_end; - struct __bootstub *bootstub = (struct __bootstub *)fake_heap_end; - u32 *bootloader = (u32*)(fake_heap_end+bootstub_bin_size); - - memcpy(bootstub,bootstub_bin,bootstub_bin_size); - memcpy(bootloader,load_bin,load_bin_size); - bool ret = false; - - bootloader[8] = isDSiMode(); - if ( havedsiSD) { - ret = true; - bootloader[3] = 0; // don't dldi patch - bootloader[7] = 1; // use internal dsi SD code - } else { - ret = dldiPatchLoader((data_t*)bootloader, load_bin_size,false); - } - bootstub->arm9reboot = (VoidFn)(((u32)bootstub->arm9reboot)+fake_heap_end); - bootstub->arm7reboot = (VoidFn)(((u32)bootstub->arm7reboot)+fake_heap_end); - bootstub->bootsize = load_bin_size; - - DC_FlushAll(); - - return ret; -#else - return true; -#endif - -} diff --git a/settings/bootloader/load.ld b/settings/bootloader/load.ld index 53f37287ea..566c3e6dd9 100644 --- a/settings/bootloader/load.ld +++ b/settings/bootloader/load.ld @@ -4,7 +4,7 @@ ENTRY(_start) MEMORY { - vram : ORIGIN = 0x06000000, LENGTH = 128K + vram : ORIGIN = 0x06008000, LENGTH = 128K - 32K } __vram_start = ORIGIN(vram); diff --git a/settings/bootloader/source/boot.c b/settings/bootloader/source/boot.c index 165be33b27..1e2a21f037 100644 --- a/settings/bootloader/source/boot.c +++ b/settings/bootloader/source/boot.c @@ -143,7 +143,7 @@ void passArgs_ARM7 (void) { argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned if (ARM9_LEN > 0x380000) { - argDst = (u32*)0x02FFA000; + argDst = (u32*)(0x02FFC000 - ((argSize/4)*4)); } else if (dsiMode && (*(u8*)(NDS_HEAD + 0x012) & BIT(1))) { u32 ARM9i_DST = *((u32*)(TWL_HEAD + 0x1C8)); @@ -448,6 +448,19 @@ int main (void) { #ifndef NO_SDMMC sdRead = (dsiSD && dsiMode); #endif + if (wantToPatchDLDI) { + toncset((u32*)0x06000000, 0, 0x8000); + if (*(u32*)0x02FF8004 == 0x69684320) { // DLDI ' Chi' string + const u16 dldiFileSize = 1 << *(u8*)0x02FF800D; + tonccpy((u32*)0x06000000, (u32*)0x02FF8000, (dldiFileSize > 0x4000) ? 0x4000 : dldiFileSize); + dldiClearBss(); + } else if (*(u32*)0x02FF8000 == 0x53535A4C) { // LZ77 flag + dldiDecompressBinary(); + } else { + return -1; + } + } + if (*(u32*)(0x2FFFD0C) == 0x4E44544C) { limitedModeMemoryPit(); *(u32*)(0x2FFFD0C) = 0; diff --git a/settings/bootloader/source/dldi_patcher.c b/settings/bootloader/source/dldi_patcher.c index 061b955728..9aa55f0024 100644 --- a/settings/bootloader/source/dldi_patcher.c +++ b/settings/bootloader/source/dldi_patcher.c @@ -22,6 +22,7 @@ #ifndef NO_DLDI #include #include +#include "common/tonccpy.h" #include "dldi_patcher.h" #define FIX_ALL 0x01 @@ -76,7 +77,7 @@ static addr_t quickFind (const data_t* data, const data_t* search, size_t dataLe addr_t i; addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int)); - for ( i = 0; i < dataChunkEnd; i++) { + for (i = 0; i < dataChunkEnd; i++) { if (dataChunk[i] == searchChunk) { if ((i*sizeof(int) + searchLen) > dataLen) { return -1; @@ -107,7 +108,7 @@ static void demangleMagicString(data_t *dest, const data_t *src) { #define DEVICE_TYPE_DLDI 0x49444C44 -extern data_t _dldi_start[]; +static data_t* _dldi_start = (data_t*)0x06000000; bool dldiPatchBinary (data_t *binData, u32 binSize) { @@ -164,7 +165,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application - memcpy (pAH, pDH, dldiFileSize); + tonccpy (pAH, pDH, dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); @@ -184,7 +185,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + tonccpy (pAH, dldiMagicString, sizeof (dldiMagicString)); if (pDH[DO_fixSections] & FIX_ALL) { // Search through and fix pointers within the data section of the file @@ -215,9 +216,96 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } return true; } + +void dldiDecompressBinary (void) { + extern void LZ77_Decompress(u8* source, u8* destination); + LZ77_Decompress((u8*)0x02FF8004, (u8*)_dldi_start); + + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + 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 = _dldi_start; + + memOffset = 0x06000000; + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Fix the section pointers in the header + writeAddr (pDH, DO_text_start, readAddr (pDH, DO_text_start) + relocationOffset); + writeAddr (pDH, DO_data_end, readAddr (pDH, DO_data_end) + relocationOffset); + writeAddr (pDH, DO_glue_start, readAddr (pDH, DO_glue_start) + relocationOffset); + writeAddr (pDH, DO_glue_end, readAddr (pDH, DO_glue_end) + relocationOffset); + writeAddr (pDH, DO_got_start, readAddr (pDH, DO_got_start) + relocationOffset); + writeAddr (pDH, DO_got_end, readAddr (pDH, DO_got_end) + relocationOffset); + writeAddr (pDH, DO_bss_start, readAddr (pDH, DO_bss_start) + relocationOffset); + writeAddr (pDH, DO_bss_end, readAddr (pDH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pDH, DO_startup, readAddr (pDH, DO_startup) + relocationOffset); + writeAddr (pDH, DO_isInserted, readAddr (pDH, DO_isInserted) + relocationOffset); + writeAddr (pDH, DO_readSectors, readAddr (pDH, DO_readSectors) + relocationOffset); + writeAddr (pDH, DO_writeSectors, readAddr (pDH, DO_writeSectors) + relocationOffset); + writeAddr (pDH, DO_clearStatus, readAddr (pDH, DO_clearStatus) + relocationOffset); + writeAddr (pDH, DO_shutdown, readAddr (pDH, DO_shutdown) + relocationOffset); + + 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} + +void dldiClearBss (void) { + data_t *pDH = _dldi_start; + + addr_t ddmemSize = (1 << pDH[DO_driverSize]); // Size of range that offsets can be in the DLDI file + + if (ddmemSize <= 0x4000) return; // For <= 16KB DLDI file, BSS has already been cleared + + addr_t ddmemStart = readAddr (pDH, DO_text_start); // Start of range that offsets can be in the DLDI file + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} #endif \ No newline at end of file diff --git a/settings/bootloader/source/dldi_patcher.h b/settings/bootloader/source/dldi_patcher.h index f54c531ba1..16ea22a859 100644 --- a/settings/bootloader/source/dldi_patcher.h +++ b/settings/bootloader/source/dldi_patcher.h @@ -28,5 +28,7 @@ typedef signed int addr_t; typedef unsigned char data_t; bool dldiPatchBinary (data_t *binData, u32 binSize); +void dldiDecompressBinary (void); +void dldiClearBss (void); #endif // DLDI_PATCHER_H diff --git a/settings/bootloader/source/io_dldi.s b/settings/bootloader/source/io_dldi.s index 08ac2cf002..82147a9140 100644 --- a/settings/bootloader/source/io_dldi.s +++ b/settings/bootloader/source/io_dldi.s @@ -32,73 +32,6 @@ _dldi_start: -#ifndef NO_DLDI - -@--------------------------------------------------------------------------------- -@ Driver patch file standard header -- 16 bytes -#ifdef STANDARD_DLDI - .word 0xBF8DA5ED @ Magic number to identify this region -#else - .word 0xBF8DA5EE @ Magic number to identify this region -#endif - .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) - .byte 0x01 @ Version number - .byte 0x0f @ 32KiB @ Log [base-2] of the size of this driver in bytes. - .byte 0x00 @ Sections to fix - .byte 0x0f @ 32KiB @ Log [base-2] of the allocated space in bytes. - -@--------------------------------------------------------------------------------- -@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes - .align 4 - .asciz "Loader (No interface)" - -@--------------------------------------------------------------------------------- -@ Offsets to important sections within the data -- 32 bytes - .align 6 - .word _dldi_start @ data start - .word _dldi_end @ data end - .word 0x00000000 @ Interworking glue start -- Needs address fixing - .word 0x00000000 @ Interworking glue end - .word 0x00000000 @ GOT start -- Needs address fixing - .word 0x00000000 @ GOT end - .word 0x00000000 @ bss start -- Needs setting to zero - .word 0x00000000 @ bss end -@--------------------------------------------------------------------------------- -@ IO_INTERFACE data -- 32 bytes -_io_dldi: - .ascii "DLDI" @ ioType - .word 0x00000000 @ Features - .word _DLDI_startup @ - .word _DLDI_isInserted @ - .word _DLDI_readSectors @ Function pointers to standard device driver functions - .word _DLDI_writeSectors @ - .word _DLDI_clearStatus @ - .word _DLDI_shutdown @ - - -@--------------------------------------------------------------------------------- - -_DLDI_startup: -_DLDI_isInserted: -_DLDI_readSectors: -_DLDI_writeSectors: -_DLDI_clearStatus: -_DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - - -@--------------------------------------------------------------------------------- - .align - .pool - - .space (_dldi_start + 32768) - . @ Fill to 32KiB - -_dldi_end: - .end -@--------------------------------------------------------------------------------- -#else @--------------------------------------------------------------------------------- @ IO_INTERFACE data -- 32 bytes _io_dldi: @@ -111,14 +44,21 @@ _io_dldi: .word _DLDI_clearStatus @ .word _DLDI_shutdown @ - _DLDI_startup: +_DLDI_startup: + mov r12, #0x06000000 + ldr pc, [r12, #0x68] _DLDI_isInserted: + mov r12, #0x06000000 + ldr pc, [r12, #0x6C] _DLDI_readSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x70] _DLDI_writeSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x74] _DLDI_clearStatus: + mov r12, #0x06000000 + ldr pc, [r12, #0x78] _DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - -#endif + mov r12, #0x06000000 + ldr pc, [r12, #0x7C] diff --git a/settings/bootloader/source/lzss.c b/settings/bootloader/source/lzss.c new file mode 100644 index 0000000000..d4a113b3d9 --- /dev/null +++ b/settings/bootloader/source/lzss.c @@ -0,0 +1,27 @@ +#include +#include + +void LZ77_Decompress(u8* source, u8* destination) { + u32 leng = (source[1] | (source[2] << 8) | (source[3] << 16)); + int Offs = 4; + int dstoffs = 0; + while (true) { + u8 header = source[Offs++]; + for (int i = 0; i < 8; i++) { + if ((header & 0x80) == 0) destination[dstoffs++] = source[Offs++]; + else + { + u8 a = source[Offs++]; + u8 b = source[Offs++]; + int offs = (((a & 0xF) << 8) | b) + 1; + int length = (a >> 4) + 3; + for (int j = 0; j < length; j++) { + destination[dstoffs] = destination[dstoffs - offs]; + dstoffs++; + } + } + if (dstoffs >= (int)leng) return; + header <<= 1; + } + } +} diff --git a/title/arm9/source/main.cpp b/title/arm9/source/main.cpp index f78ee52cfe..f86a7ebd59 100644 --- a/title/arm9/source/main.cpp +++ b/title/arm9/source/main.cpp @@ -1820,6 +1820,18 @@ int titleMode(void) 4: Run temporary DSiWare */ + if ((strcmp(io_dldi_data->friendlyName, "NAND FLASH CARD LIBFATNRIO") == 0) && (*(u32*)0x02FF8000 != 0x53535A4C)) { + FILE* file = fopen("nitro:/dldi/nrio.lz77", "rb"); + fread((void*)0x02FF8004, 1, 0x3FFC, file); + fclose(file); + + *(u32*)0x02FF8000 = 0x53535A4C; + } + + #ifndef _NO_BOOTSTUB_ + installBootStub(sdFound()); + #endif + if (isDSiMode() && sdFound()) { if ((access("sd:/_nds/bios9i.bin", F_OK) != 0) && (access("sd:/_nds/bios9i_part1.bin", F_OK) != 0)) { extern char copyBuf[0x8000]; @@ -1884,7 +1896,7 @@ int titleMode(void) } } - bool is3DS = fifoGetValue32(FIFO_USER_05) != 0xD2; + const bool is3DS = fifoGetValue32(FIFO_USER_05) != 0xD2; useTwlCfg = (REG_SCFG_EXT!=0 && (*(u8*)0x02000400 != 0) && (*(u8*)0x02000401 == 0) && (*(u8*)0x02000402 == 0) && (*(u8*)0x02000404 == 0) && (*(u8*)0x02000448 != 0)); bool nandMounted = false; diff --git a/title/bootloader/load.ld b/title/bootloader/load.ld index 53f37287ea..566c3e6dd9 100644 --- a/title/bootloader/load.ld +++ b/title/bootloader/load.ld @@ -4,7 +4,7 @@ ENTRY(_start) MEMORY { - vram : ORIGIN = 0x06000000, LENGTH = 128K + vram : ORIGIN = 0x06008000, LENGTH = 128K - 32K } __vram_start = ORIGIN(vram); diff --git a/title/bootloader/source/boot.c b/title/bootloader/source/boot.c index 5c33316c2d..2aa0b38400 100644 --- a/title/bootloader/source/boot.c +++ b/title/bootloader/source/boot.c @@ -148,7 +148,7 @@ void passArgs_ARM7 (void) { argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned if (ARM9_LEN > 0x380000) { - argDst = (u32*)0x02FFA000; + argDst = (u32*)(0x02FFC000 - ((argSize/4)*4)); } else if (dsiMode && (*(u8*)(NDS_HEAD + 0x012) & BIT(1))) { u32 ARM9i_DST = *((u32*)(TWL_HEAD + 0x1C8)); u32 ARM9i_LEN = *((u32*)(TWL_HEAD + 0x1CC)); @@ -635,6 +635,19 @@ int main (void) { #ifndef NO_SDMMC sdRead = (dsiSD && dsiMode); #endif + if (wantToPatchDLDI) { + toncset((u32*)0x06000000, 0, 0x8000); + if (*(u32*)0x02FF8004 == 0x69684320) { // DLDI ' Chi' string + const u16 dldiFileSize = 1 << *(u8*)0x02FF800D; + tonccpy((u32*)0x06000000, (u32*)0x02FF8000, (dldiFileSize > 0x4000) ? 0x4000 : dldiFileSize); + dldiClearBss(); + } else if (*(u32*)0x02FF8000 == 0x53535A4C) { // LZ77 flag + dldiDecompressBinary(); + } else { + return -1; + } + } + if (*(u32*)(0x2FFFD0C) == 0x4E44544C) { limitedModeMemoryPit(); *(u32*)(0x2FFFD0C) = 0; diff --git a/title/bootloader/source/dldi_patcher.c b/title/bootloader/source/dldi_patcher.c index 69f292e436..9aa55f0024 100644 --- a/title/bootloader/source/dldi_patcher.c +++ b/title/bootloader/source/dldi_patcher.c @@ -22,6 +22,7 @@ #ifndef NO_DLDI #include #include +#include "common/tonccpy.h" #include "dldi_patcher.h" #define FIX_ALL 0x01 @@ -107,7 +108,7 @@ static void demangleMagicString(data_t *dest, const data_t *src) { #define DEVICE_TYPE_DLDI 0x49444C44 -extern data_t _dldi_start[]; +static data_t* _dldi_start = (data_t*)0x06000000; bool dldiPatchBinary (data_t *binData, u32 binSize) { @@ -164,7 +165,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application - memcpy (pAH, pDH, dldiFileSize); + tonccpy (pAH, pDH, dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); @@ -184,7 +185,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + tonccpy (pAH, dldiMagicString, sizeof (dldiMagicString)); if (pDH[DO_fixSections] & FIX_ALL) { // Search through and fix pointers within the data section of the file @@ -215,9 +216,96 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } return true; } + +void dldiDecompressBinary (void) { + extern void LZ77_Decompress(u8* source, u8* destination); + LZ77_Decompress((u8*)0x02FF8004, (u8*)_dldi_start); + + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + 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 = _dldi_start; + + memOffset = 0x06000000; + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Fix the section pointers in the header + writeAddr (pDH, DO_text_start, readAddr (pDH, DO_text_start) + relocationOffset); + writeAddr (pDH, DO_data_end, readAddr (pDH, DO_data_end) + relocationOffset); + writeAddr (pDH, DO_glue_start, readAddr (pDH, DO_glue_start) + relocationOffset); + writeAddr (pDH, DO_glue_end, readAddr (pDH, DO_glue_end) + relocationOffset); + writeAddr (pDH, DO_got_start, readAddr (pDH, DO_got_start) + relocationOffset); + writeAddr (pDH, DO_got_end, readAddr (pDH, DO_got_end) + relocationOffset); + writeAddr (pDH, DO_bss_start, readAddr (pDH, DO_bss_start) + relocationOffset); + writeAddr (pDH, DO_bss_end, readAddr (pDH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pDH, DO_startup, readAddr (pDH, DO_startup) + relocationOffset); + writeAddr (pDH, DO_isInserted, readAddr (pDH, DO_isInserted) + relocationOffset); + writeAddr (pDH, DO_readSectors, readAddr (pDH, DO_readSectors) + relocationOffset); + writeAddr (pDH, DO_writeSectors, readAddr (pDH, DO_writeSectors) + relocationOffset); + writeAddr (pDH, DO_clearStatus, readAddr (pDH, DO_clearStatus) + relocationOffset); + writeAddr (pDH, DO_shutdown, readAddr (pDH, DO_shutdown) + relocationOffset); + + 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} + +void dldiClearBss (void) { + data_t *pDH = _dldi_start; + + addr_t ddmemSize = (1 << pDH[DO_driverSize]); // Size of range that offsets can be in the DLDI file + + if (ddmemSize <= 0x4000) return; // For <= 16KB DLDI file, BSS has already been cleared + + addr_t ddmemStart = readAddr (pDH, DO_text_start); // Start of range that offsets can be in the DLDI file + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} #endif \ No newline at end of file diff --git a/title/bootloader/source/dldi_patcher.h b/title/bootloader/source/dldi_patcher.h index f54c531ba1..16ea22a859 100644 --- a/title/bootloader/source/dldi_patcher.h +++ b/title/bootloader/source/dldi_patcher.h @@ -28,5 +28,7 @@ typedef signed int addr_t; typedef unsigned char data_t; bool dldiPatchBinary (data_t *binData, u32 binSize); +void dldiDecompressBinary (void); +void dldiClearBss (void); #endif // DLDI_PATCHER_H diff --git a/title/bootloader/source/io_dldi.s b/title/bootloader/source/io_dldi.s index 08ac2cf002..82147a9140 100644 --- a/title/bootloader/source/io_dldi.s +++ b/title/bootloader/source/io_dldi.s @@ -32,73 +32,6 @@ _dldi_start: -#ifndef NO_DLDI - -@--------------------------------------------------------------------------------- -@ Driver patch file standard header -- 16 bytes -#ifdef STANDARD_DLDI - .word 0xBF8DA5ED @ Magic number to identify this region -#else - .word 0xBF8DA5EE @ Magic number to identify this region -#endif - .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) - .byte 0x01 @ Version number - .byte 0x0f @ 32KiB @ Log [base-2] of the size of this driver in bytes. - .byte 0x00 @ Sections to fix - .byte 0x0f @ 32KiB @ Log [base-2] of the allocated space in bytes. - -@--------------------------------------------------------------------------------- -@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes - .align 4 - .asciz "Loader (No interface)" - -@--------------------------------------------------------------------------------- -@ Offsets to important sections within the data -- 32 bytes - .align 6 - .word _dldi_start @ data start - .word _dldi_end @ data end - .word 0x00000000 @ Interworking glue start -- Needs address fixing - .word 0x00000000 @ Interworking glue end - .word 0x00000000 @ GOT start -- Needs address fixing - .word 0x00000000 @ GOT end - .word 0x00000000 @ bss start -- Needs setting to zero - .word 0x00000000 @ bss end -@--------------------------------------------------------------------------------- -@ IO_INTERFACE data -- 32 bytes -_io_dldi: - .ascii "DLDI" @ ioType - .word 0x00000000 @ Features - .word _DLDI_startup @ - .word _DLDI_isInserted @ - .word _DLDI_readSectors @ Function pointers to standard device driver functions - .word _DLDI_writeSectors @ - .word _DLDI_clearStatus @ - .word _DLDI_shutdown @ - - -@--------------------------------------------------------------------------------- - -_DLDI_startup: -_DLDI_isInserted: -_DLDI_readSectors: -_DLDI_writeSectors: -_DLDI_clearStatus: -_DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - - -@--------------------------------------------------------------------------------- - .align - .pool - - .space (_dldi_start + 32768) - . @ Fill to 32KiB - -_dldi_end: - .end -@--------------------------------------------------------------------------------- -#else @--------------------------------------------------------------------------------- @ IO_INTERFACE data -- 32 bytes _io_dldi: @@ -111,14 +44,21 @@ _io_dldi: .word _DLDI_clearStatus @ .word _DLDI_shutdown @ - _DLDI_startup: +_DLDI_startup: + mov r12, #0x06000000 + ldr pc, [r12, #0x68] _DLDI_isInserted: + mov r12, #0x06000000 + ldr pc, [r12, #0x6C] _DLDI_readSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x70] _DLDI_writeSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x74] _DLDI_clearStatus: + mov r12, #0x06000000 + ldr pc, [r12, #0x78] _DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - -#endif + mov r12, #0x06000000 + ldr pc, [r12, #0x7C] diff --git a/title/bootloader/source/load_crt0.s b/title/bootloader/source/load_crt0.s index bb841834c1..aa1b015ae3 100644 --- a/title/bootloader/source/load_crt0.s +++ b/title/bootloader/source/load_crt0.s @@ -55,7 +55,7 @@ argStart: argSize: .word 0x00000000 dldiOffset: - .word _dldi_start - _start + .word 0 dsiSD: .word 0 dsiMode: diff --git a/title/bootloader/source/lzss.c b/title/bootloader/source/lzss.c new file mode 100644 index 0000000000..d4a113b3d9 --- /dev/null +++ b/title/bootloader/source/lzss.c @@ -0,0 +1,27 @@ +#include +#include + +void LZ77_Decompress(u8* source, u8* destination) { + u32 leng = (source[1] | (source[2] << 8) | (source[3] << 16)); + int Offs = 4; + int dstoffs = 0; + while (true) { + u8 header = source[Offs++]; + for (int i = 0; i < 8; i++) { + if ((header & 0x80) == 0) destination[dstoffs++] = source[Offs++]; + else + { + u8 a = source[Offs++]; + u8 b = source[Offs++]; + int offs = (((a & 0xF) << 8) | b) + 1; + int length = (a >> 4) + 3; + for (int j = 0; j < length; j++) { + destination[dstoffs] = destination[dstoffs - offs]; + dstoffs++; + } + } + if (dstoffs >= (int)leng) return; + header <<= 1; + } + } +} diff --git a/title/nitrofiles/dldi/nrio.lz77 b/title/nitrofiles/dldi/nrio.lz77 new file mode 100644 index 0000000000..fc556a403e Binary files /dev/null and b/title/nitrofiles/dldi/nrio.lz77 differ diff --git a/universal/bootloader_app/load.ld b/universal/bootloader_app/load.ld index 53f37287ea..566c3e6dd9 100644 --- a/universal/bootloader_app/load.ld +++ b/universal/bootloader_app/load.ld @@ -4,7 +4,7 @@ ENTRY(_start) MEMORY { - vram : ORIGIN = 0x06000000, LENGTH = 128K + vram : ORIGIN = 0x06008000, LENGTH = 128K - 32K } __vram_start = ORIGIN(vram); diff --git a/universal/bootloader_app/source/boot.c b/universal/bootloader_app/source/boot.c index 314ac9bb49..17b5218703 100644 --- a/universal/bootloader_app/source/boot.c +++ b/universal/bootloader_app/source/boot.c @@ -388,6 +388,19 @@ int main (void) { #ifndef NO_SDMMC sdRead = (dsiSD && dsiMode); #endif + if (wantToPatchDLDI) { + toncset((u32*)0x06000000, 0, 0x8000); + if (*(u32*)0x02FF8004 == 0x69684320) { // DLDI ' Chi' string + const u16 dldiFileSize = 1 << *(u8*)0x02FF800D; + tonccpy((u32*)0x06000000, (u32*)0x02FF8000, (dldiFileSize > 0x4000) ? 0x4000 : dldiFileSize); + dldiClearBss(); + } else if (*(u32*)0x02FF8000 == 0x53535A4C) { // LZ77 flag + dldiDecompressBinary(); + } else { + return -1; + } + } + u32 fileCluster = storedFileCluster; if (!loadFromRam) { // Init card diff --git a/universal/bootloader_app/source/dldi_patcher.c b/universal/bootloader_app/source/dldi_patcher.c index 69f292e436..9aa55f0024 100644 --- a/universal/bootloader_app/source/dldi_patcher.c +++ b/universal/bootloader_app/source/dldi_patcher.c @@ -22,6 +22,7 @@ #ifndef NO_DLDI #include #include +#include "common/tonccpy.h" #include "dldi_patcher.h" #define FIX_ALL 0x01 @@ -107,7 +108,7 @@ static void demangleMagicString(data_t *dest, const data_t *src) { #define DEVICE_TYPE_DLDI 0x49444C44 -extern data_t _dldi_start[]; +static data_t* _dldi_start = (data_t*)0x06000000; bool dldiPatchBinary (data_t *binData, u32 binSize) { @@ -164,7 +165,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application - memcpy (pAH, pDH, dldiFileSize); + tonccpy (pAH, pDH, dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); @@ -184,7 +185,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + tonccpy (pAH, dldiMagicString, sizeof (dldiMagicString)); if (pDH[DO_fixSections] & FIX_ALL) { // Search through and fix pointers within the data section of the file @@ -215,9 +216,96 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } return true; } + +void dldiDecompressBinary (void) { + extern void LZ77_Decompress(u8* source, u8* destination); + LZ77_Decompress((u8*)0x02FF8004, (u8*)_dldi_start); + + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + 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 = _dldi_start; + + memOffset = 0x06000000; + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Fix the section pointers in the header + writeAddr (pDH, DO_text_start, readAddr (pDH, DO_text_start) + relocationOffset); + writeAddr (pDH, DO_data_end, readAddr (pDH, DO_data_end) + relocationOffset); + writeAddr (pDH, DO_glue_start, readAddr (pDH, DO_glue_start) + relocationOffset); + writeAddr (pDH, DO_glue_end, readAddr (pDH, DO_glue_end) + relocationOffset); + writeAddr (pDH, DO_got_start, readAddr (pDH, DO_got_start) + relocationOffset); + writeAddr (pDH, DO_got_end, readAddr (pDH, DO_got_end) + relocationOffset); + writeAddr (pDH, DO_bss_start, readAddr (pDH, DO_bss_start) + relocationOffset); + writeAddr (pDH, DO_bss_end, readAddr (pDH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pDH, DO_startup, readAddr (pDH, DO_startup) + relocationOffset); + writeAddr (pDH, DO_isInserted, readAddr (pDH, DO_isInserted) + relocationOffset); + writeAddr (pDH, DO_readSectors, readAddr (pDH, DO_readSectors) + relocationOffset); + writeAddr (pDH, DO_writeSectors, readAddr (pDH, DO_writeSectors) + relocationOffset); + writeAddr (pDH, DO_clearStatus, readAddr (pDH, DO_clearStatus) + relocationOffset); + writeAddr (pDH, DO_shutdown, readAddr (pDH, DO_shutdown) + relocationOffset); + + 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} + +void dldiClearBss (void) { + data_t *pDH = _dldi_start; + + addr_t ddmemSize = (1 << pDH[DO_driverSize]); // Size of range that offsets can be in the DLDI file + + if (ddmemSize <= 0x4000) return; // For <= 16KB DLDI file, BSS has already been cleared + + addr_t ddmemStart = readAddr (pDH, DO_text_start); // Start of range that offsets can be in the DLDI file + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} #endif \ No newline at end of file diff --git a/universal/bootloader_app/source/dldi_patcher.h b/universal/bootloader_app/source/dldi_patcher.h index f54c531ba1..16ea22a859 100644 --- a/universal/bootloader_app/source/dldi_patcher.h +++ b/universal/bootloader_app/source/dldi_patcher.h @@ -28,5 +28,7 @@ typedef signed int addr_t; typedef unsigned char data_t; bool dldiPatchBinary (data_t *binData, u32 binSize); +void dldiDecompressBinary (void); +void dldiClearBss (void); #endif // DLDI_PATCHER_H diff --git a/universal/bootloader_app/source/io_dldi.s b/universal/bootloader_app/source/io_dldi.s index 08ac2cf002..82147a9140 100644 --- a/universal/bootloader_app/source/io_dldi.s +++ b/universal/bootloader_app/source/io_dldi.s @@ -32,73 +32,6 @@ _dldi_start: -#ifndef NO_DLDI - -@--------------------------------------------------------------------------------- -@ Driver patch file standard header -- 16 bytes -#ifdef STANDARD_DLDI - .word 0xBF8DA5ED @ Magic number to identify this region -#else - .word 0xBF8DA5EE @ Magic number to identify this region -#endif - .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) - .byte 0x01 @ Version number - .byte 0x0f @ 32KiB @ Log [base-2] of the size of this driver in bytes. - .byte 0x00 @ Sections to fix - .byte 0x0f @ 32KiB @ Log [base-2] of the allocated space in bytes. - -@--------------------------------------------------------------------------------- -@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes - .align 4 - .asciz "Loader (No interface)" - -@--------------------------------------------------------------------------------- -@ Offsets to important sections within the data -- 32 bytes - .align 6 - .word _dldi_start @ data start - .word _dldi_end @ data end - .word 0x00000000 @ Interworking glue start -- Needs address fixing - .word 0x00000000 @ Interworking glue end - .word 0x00000000 @ GOT start -- Needs address fixing - .word 0x00000000 @ GOT end - .word 0x00000000 @ bss start -- Needs setting to zero - .word 0x00000000 @ bss end -@--------------------------------------------------------------------------------- -@ IO_INTERFACE data -- 32 bytes -_io_dldi: - .ascii "DLDI" @ ioType - .word 0x00000000 @ Features - .word _DLDI_startup @ - .word _DLDI_isInserted @ - .word _DLDI_readSectors @ Function pointers to standard device driver functions - .word _DLDI_writeSectors @ - .word _DLDI_clearStatus @ - .word _DLDI_shutdown @ - - -@--------------------------------------------------------------------------------- - -_DLDI_startup: -_DLDI_isInserted: -_DLDI_readSectors: -_DLDI_writeSectors: -_DLDI_clearStatus: -_DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - - -@--------------------------------------------------------------------------------- - .align - .pool - - .space (_dldi_start + 32768) - . @ Fill to 32KiB - -_dldi_end: - .end -@--------------------------------------------------------------------------------- -#else @--------------------------------------------------------------------------------- @ IO_INTERFACE data -- 32 bytes _io_dldi: @@ -111,14 +44,21 @@ _io_dldi: .word _DLDI_clearStatus @ .word _DLDI_shutdown @ - _DLDI_startup: +_DLDI_startup: + mov r12, #0x06000000 + ldr pc, [r12, #0x68] _DLDI_isInserted: + mov r12, #0x06000000 + ldr pc, [r12, #0x6C] _DLDI_readSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x70] _DLDI_writeSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x74] _DLDI_clearStatus: + mov r12, #0x06000000 + ldr pc, [r12, #0x78] _DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - -#endif + mov r12, #0x06000000 + ldr pc, [r12, #0x7C] diff --git a/universal/bootloader_app/source/lzss.c b/universal/bootloader_app/source/lzss.c new file mode 100644 index 0000000000..d4a113b3d9 --- /dev/null +++ b/universal/bootloader_app/source/lzss.c @@ -0,0 +1,27 @@ +#include +#include + +void LZ77_Decompress(u8* source, u8* destination) { + u32 leng = (source[1] | (source[2] << 8) | (source[3] << 16)); + int Offs = 4; + int dstoffs = 0; + while (true) { + u8 header = source[Offs++]; + for (int i = 0; i < 8; i++) { + if ((header & 0x80) == 0) destination[dstoffs++] = source[Offs++]; + else + { + u8 a = source[Offs++]; + u8 b = source[Offs++]; + int offs = (((a & 0xF) << 8) | b) + 1; + int length = (a >> 4) + 3; + for (int j = 0; j < length; j++) { + destination[dstoffs] = destination[dstoffs - offs]; + dstoffs++; + } + } + if (dstoffs >= (int)leng) return; + header <<= 1; + } + } +} diff --git a/universal/bootloader_menu/load.ld b/universal/bootloader_menu/load.ld index 53f37287ea..566c3e6dd9 100644 --- a/universal/bootloader_menu/load.ld +++ b/universal/bootloader_menu/load.ld @@ -4,7 +4,7 @@ ENTRY(_start) MEMORY { - vram : ORIGIN = 0x06000000, LENGTH = 128K + vram : ORIGIN = 0x06008000, LENGTH = 128K - 32K } __vram_start = ORIGIN(vram); diff --git a/universal/bootloader_menu/source/boot.c b/universal/bootloader_menu/source/boot.c index 0849a578e7..5fb22323c8 100644 --- a/universal/bootloader_menu/source/boot.c +++ b/universal/bootloader_menu/source/boot.c @@ -148,7 +148,7 @@ void passArgs_ARM7 (void) { argDst = (u32*)((ARM9_DST + ARM9_LEN + 3) & ~3); // Word aligned if (ARM9_LEN > 0x380000) { - argDst = (u32*)0x02FFA000; + argDst = (u32*)(0x02FFC000 - ((argSize/4)*4)); } else if (dsiMode && (*(u8*)(NDS_HEAD + 0x012) & BIT(1))) { u32 ARM9i_DST = *((u32*)(TWL_HEAD + 0x1C8)); @@ -579,6 +579,19 @@ int main (void) { #ifndef NO_SDMMC sdRead = (dsiSD && dsiMode); #endif + if (wantToPatchDLDI) { + toncset((u32*)0x06000000, 0, 0x8000); + if (*(u32*)0x02FF8004 == 0x69684320) { // DLDI ' Chi' string + const u16 dldiFileSize = 1 << *(u8*)0x02FF800D; + tonccpy((u32*)0x06000000, (u32*)0x02FF8000, (dldiFileSize > 0x4000) ? 0x4000 : dldiFileSize); + dldiClearBss(); + } else if (*(u32*)0x02FF8000 == 0x53535A4C) { // LZ77 flag + dldiDecompressBinary(); + } else { + return -1; + } + } + u32 fileCluster = storedFileCluster; if (!loadFromRam) { // Init card diff --git a/universal/bootloader_menu/source/dldi_patcher.c b/universal/bootloader_menu/source/dldi_patcher.c index 69f292e436..9aa55f0024 100644 --- a/universal/bootloader_menu/source/dldi_patcher.c +++ b/universal/bootloader_menu/source/dldi_patcher.c @@ -22,6 +22,7 @@ #ifndef NO_DLDI #include #include +#include "common/tonccpy.h" #include "dldi_patcher.h" #define FIX_ALL 0x01 @@ -107,7 +108,7 @@ static void demangleMagicString(data_t *dest, const data_t *src) { #define DEVICE_TYPE_DLDI 0x49444C44 -extern data_t _dldi_start[]; +static data_t* _dldi_start = (data_t*)0x06000000; bool dldiPatchBinary (data_t *binData, u32 binSize) { @@ -164,7 +165,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application - memcpy (pAH, pDH, dldiFileSize); + tonccpy (pAH, pDH, dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); @@ -184,7 +185,7 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + tonccpy (pAH, dldiMagicString, sizeof (dldiMagicString)); if (pDH[DO_fixSections] & FIX_ALL) { // Search through and fix pointers within the data section of the file @@ -215,9 +216,96 @@ bool dldiPatchBinary (data_t *binData, u32 binSize) { 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)); + toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } return true; } + +void dldiDecompressBinary (void) { + extern void LZ77_Decompress(u8* source, u8* destination); + LZ77_Decompress((u8*)0x02FF8004, (u8*)_dldi_start); + + addr_t memOffset; // Offset of DLDI after the file is loaded into memory + 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 = _dldi_start; + + memOffset = 0x06000000; + ddmemOffset = readAddr (pDH, DO_text_start); + relocationOffset = memOffset - ddmemOffset; + + ddmemStart = readAddr (pDH, DO_text_start); + ddmemSize = (1 << pDH[DO_driverSize]); + ddmemEnd = ddmemStart + ddmemSize; + + // Fix the section pointers in the header + writeAddr (pDH, DO_text_start, readAddr (pDH, DO_text_start) + relocationOffset); + writeAddr (pDH, DO_data_end, readAddr (pDH, DO_data_end) + relocationOffset); + writeAddr (pDH, DO_glue_start, readAddr (pDH, DO_glue_start) + relocationOffset); + writeAddr (pDH, DO_glue_end, readAddr (pDH, DO_glue_end) + relocationOffset); + writeAddr (pDH, DO_got_start, readAddr (pDH, DO_got_start) + relocationOffset); + writeAddr (pDH, DO_got_end, readAddr (pDH, DO_got_end) + relocationOffset); + writeAddr (pDH, DO_bss_start, readAddr (pDH, DO_bss_start) + relocationOffset); + writeAddr (pDH, DO_bss_end, readAddr (pDH, DO_bss_end) + relocationOffset); + // Fix the function pointers in the header + writeAddr (pDH, DO_startup, readAddr (pDH, DO_startup) + relocationOffset); + writeAddr (pDH, DO_isInserted, readAddr (pDH, DO_isInserted) + relocationOffset); + writeAddr (pDH, DO_readSectors, readAddr (pDH, DO_readSectors) + relocationOffset); + writeAddr (pDH, DO_writeSectors, readAddr (pDH, DO_writeSectors) + relocationOffset); + writeAddr (pDH, DO_clearStatus, readAddr (pDH, DO_clearStatus) + relocationOffset); + writeAddr (pDH, DO_shutdown, readAddr (pDH, DO_shutdown) + relocationOffset); + + 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, 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(pDH, addrIter)) && (readAddr(pDH, addrIter) < ddmemEnd)) { + writeAddr (pDH, addrIter, readAddr(pDH, addrIter) + relocationOffset); + } + } + } + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} + +void dldiClearBss (void) { + data_t *pDH = _dldi_start; + + addr_t ddmemSize = (1 << pDH[DO_driverSize]); // Size of range that offsets can be in the DLDI file + + if (ddmemSize <= 0x4000) return; // For <= 16KB DLDI file, BSS has already been cleared + + addr_t ddmemStart = readAddr (pDH, DO_text_start); // Start of range that offsets can be in the DLDI file + + if (pDH[DO_fixSections] & FIX_BSS) { + // Initialise the BSS to 0 + toncset (&pDH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); + } +} #endif \ No newline at end of file diff --git a/universal/bootloader_menu/source/dldi_patcher.h b/universal/bootloader_menu/source/dldi_patcher.h index f54c531ba1..16ea22a859 100644 --- a/universal/bootloader_menu/source/dldi_patcher.h +++ b/universal/bootloader_menu/source/dldi_patcher.h @@ -28,5 +28,7 @@ typedef signed int addr_t; typedef unsigned char data_t; bool dldiPatchBinary (data_t *binData, u32 binSize); +void dldiDecompressBinary (void); +void dldiClearBss (void); #endif // DLDI_PATCHER_H diff --git a/universal/bootloader_menu/source/io_dldi.s b/universal/bootloader_menu/source/io_dldi.s index 08ac2cf002..82147a9140 100644 --- a/universal/bootloader_menu/source/io_dldi.s +++ b/universal/bootloader_menu/source/io_dldi.s @@ -32,73 +32,6 @@ _dldi_start: -#ifndef NO_DLDI - -@--------------------------------------------------------------------------------- -@ Driver patch file standard header -- 16 bytes -#ifdef STANDARD_DLDI - .word 0xBF8DA5ED @ Magic number to identify this region -#else - .word 0xBF8DA5EE @ Magic number to identify this region -#endif - .asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator) - .byte 0x01 @ Version number - .byte 0x0f @ 32KiB @ Log [base-2] of the size of this driver in bytes. - .byte 0x00 @ Sections to fix - .byte 0x0f @ 32KiB @ Log [base-2] of the allocated space in bytes. - -@--------------------------------------------------------------------------------- -@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes - .align 4 - .asciz "Loader (No interface)" - -@--------------------------------------------------------------------------------- -@ Offsets to important sections within the data -- 32 bytes - .align 6 - .word _dldi_start @ data start - .word _dldi_end @ data end - .word 0x00000000 @ Interworking glue start -- Needs address fixing - .word 0x00000000 @ Interworking glue end - .word 0x00000000 @ GOT start -- Needs address fixing - .word 0x00000000 @ GOT end - .word 0x00000000 @ bss start -- Needs setting to zero - .word 0x00000000 @ bss end -@--------------------------------------------------------------------------------- -@ IO_INTERFACE data -- 32 bytes -_io_dldi: - .ascii "DLDI" @ ioType - .word 0x00000000 @ Features - .word _DLDI_startup @ - .word _DLDI_isInserted @ - .word _DLDI_readSectors @ Function pointers to standard device driver functions - .word _DLDI_writeSectors @ - .word _DLDI_clearStatus @ - .word _DLDI_shutdown @ - - -@--------------------------------------------------------------------------------- - -_DLDI_startup: -_DLDI_isInserted: -_DLDI_readSectors: -_DLDI_writeSectors: -_DLDI_clearStatus: -_DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - - -@--------------------------------------------------------------------------------- - .align - .pool - - .space (_dldi_start + 32768) - . @ Fill to 32KiB - -_dldi_end: - .end -@--------------------------------------------------------------------------------- -#else @--------------------------------------------------------------------------------- @ IO_INTERFACE data -- 32 bytes _io_dldi: @@ -111,14 +44,21 @@ _io_dldi: .word _DLDI_clearStatus @ .word _DLDI_shutdown @ - _DLDI_startup: +_DLDI_startup: + mov r12, #0x06000000 + ldr pc, [r12, #0x68] _DLDI_isInserted: + mov r12, #0x06000000 + ldr pc, [r12, #0x6C] _DLDI_readSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x70] _DLDI_writeSectors: + mov r12, #0x06000000 + ldr pc, [r12, #0x74] _DLDI_clearStatus: + mov r12, #0x06000000 + ldr pc, [r12, #0x78] _DLDI_shutdown: - mov r0, #0x00 @ Return false for every function - bx lr - - -#endif + mov r12, #0x06000000 + ldr pc, [r12, #0x7C] diff --git a/universal/bootloader_menu/source/load_crt0.s b/universal/bootloader_menu/source/load_crt0.s index bb841834c1..aa1b015ae3 100644 --- a/universal/bootloader_menu/source/load_crt0.s +++ b/universal/bootloader_menu/source/load_crt0.s @@ -55,7 +55,7 @@ argStart: argSize: .word 0x00000000 dldiOffset: - .word _dldi_start - _start + .word 0 dsiSD: .word 0 dsiMode: diff --git a/universal/bootloader_menu/source/lzss.c b/universal/bootloader_menu/source/lzss.c new file mode 100644 index 0000000000..d4a113b3d9 --- /dev/null +++ b/universal/bootloader_menu/source/lzss.c @@ -0,0 +1,27 @@ +#include +#include + +void LZ77_Decompress(u8* source, u8* destination) { + u32 leng = (source[1] | (source[2] << 8) | (source[3] << 16)); + int Offs = 4; + int dstoffs = 0; + while (true) { + u8 header = source[Offs++]; + for (int i = 0; i < 8; i++) { + if ((header & 0x80) == 0) destination[dstoffs++] = source[Offs++]; + else + { + u8 a = source[Offs++]; + u8 b = source[Offs++]; + int offs = (((a & 0xF) << 8) | b) + 1; + int length = (a >> 4) + 3; + for (int j = 0; j < length; j++) { + destination[dstoffs] = destination[dstoffs - offs]; + dstoffs++; + } + } + if (dstoffs >= (int)leng) return; + header <<= 1; + } + } +} diff --git a/universal/bootstub/bootstub.s b/universal/bootstub/bootstub.s index 579fb9904d..a1ec52b674 100644 --- a/universal/bootstub/bootstub.s +++ b/universal/bootstub/bootstub.s @@ -122,7 +122,7 @@ hook7from9: adr r0, _loader ldr r2, _loader_size mov r1, #0x06800000 - add r1, r1, #0x40000 + add r1, r1, #0x48000 add r2, r0, r2 _copyloader: ldr r4, [r0], #4 @@ -140,6 +140,7 @@ _copyloader: ldr r0, arm7bootaddr mov r1, #0x06000000 + add r1, r1, #0x8000 str r1, [r0] ldr r0, resetcode diff --git a/universal/include/common/nds_loader_arm9.h b/universal/include/common/nds_loader_arm9.h index fd56741ead..05f7ea1b19 100644 --- a/universal/include/common/nds_loader_arm9.h +++ b/universal/include/common/nds_loader_arm9.h @@ -34,7 +34,7 @@ int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool int runNdsFile (const char* filename, int argc, const char** argv, bool dldiPatchNds, bool clearMasterBright, bool dsModeSwitch, bool boostCpu, bool boostVram, bool tscTgds, int language); -bool installBootStub(bool havedsiSD); +void installBootStub(bool havedsiSD); #ifdef __cplusplus } diff --git a/universal/source/nds_loader/nds_loader_arm9.c b/universal/source/nds_loader/nds_loader_arm9.c index 52e822db50..dab7d8bb73 100644 --- a/universal/source/nds_loader/nds_loader_arm9.c +++ b/universal/source/nds_loader/nds_loader_arm9.c @@ -36,7 +36,7 @@ #endif #include "common/nds_loader_arm9.h" -#define LCDC_BANK_C (u16*)0x06840000 +#define LCDC_BANK_C (u16*)0x06848000 #define STORED_FILE_CLUSTER (*(((u32*)LCDC_BANK_C) + 1)) #define INIT_DISC (*(((u32*)LCDC_BANK_C) + 2)) #define WANT_TO_PATCH_DLDI (*(((u32*)LCDC_BANK_C) + 3)) @@ -126,7 +126,7 @@ 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) { +/* 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; @@ -144,18 +144,17 @@ static addr_t quickFind (const data_t* data, const data_t* search, size_t dataLe } return -1; -} +} */ // Normal DLDI uses "\xED\xA5\x8D\xBF Chishm" // Bootloader string is different to avoid being patched -static const data_t dldiMagicLoaderString[] = "\xEE\xA5\x8D\xBF Chishm"; // Different to a normal DLDI file +// static const data_t dldiMagicLoaderString[] = "\xEE\xA5\x8D\xBF Chishm"; // Different to a normal DLDI file #define DEVICE_TYPE_DLDI 0x49444C44 -static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) +static bool dldiPatchLoader (void) { 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 @@ -164,39 +163,28 @@ static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) addr_t addrIter; - data_t *pDH; - data_t *pAH; - size_t dldiFileSize = 0; - // Find the DLDI reserved space in the file - patchOffset = quickFind (binData, dldiMagicLoaderString, binSize, sizeof(dldiMagicLoaderString)); + data_t *pDH = (data_t*)(io_dldi_data); - if (patchOffset < 0) { - // does not have a DLDI section - return false; - } - - pDH = (data_t*)(io_dldi_data); - - pAH = &(binData[patchOffset]); + data_t *pAH = (data_t*)0x02FF8000; 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; + if (*(u32*)0x02FF8004 == 0x69684320 || *(u32*)0x02FF8000 == 0x53535A4C) { + return true; // Skip patching for existing or compressed DLDI file } dldiFileSize = 1 << pDH[DO_driverSize]; - memOffset = readAddr (pAH, DO_text_start); + /* memOffset = readAddr (pAH, DO_text_start); if (memOffset == 0) { memOffset = readAddr (pAH, DO_startup) - DO_code; - } + } */ + memOffset = 0x06000000; ddmemOffset = readAddr (pDH, DO_text_start); relocationOffset = memOffset - ddmemOffset; @@ -207,7 +195,7 @@ static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) // Remember how much space is actually reserved pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace]; // Copy the DLDI patch into the application - tonccpy (pAH, pDH, dldiFileSize); + tonccpy (pAH, pDH, (dldiFileSize > 0x4000) ? 0x4000 : dldiFileSize); // Fix the section pointers in the header writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset); @@ -253,7 +241,7 @@ static bool dldiPatchLoader (data_t *binData, u32 binSize, bool clearBSS) } } - if (clearBSS && (pDH[DO_fixSections] & FIX_BSS)) { + if (/* clearBSS && */ (pDH[DO_fixSections] & FIX_BSS) && dldiFileSize <= 0x4000) { // Initialise the BSS to 0, only if the disc is being re-inited toncset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start)); } @@ -328,7 +316,7 @@ int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool if (dldiPatchNds) { // Patch the loader with a DLDI for the card - if (!dldiPatchLoader ((data_t*)LCDC_BANK_C, loaderSize, initDisc)) { + if (!dldiPatchLoader ()) { return 3; } } @@ -354,7 +342,7 @@ int runNds (const void* loader, u32 loaderSize, u32 cluster, bool initDisc, bool *((vu32*)0x02FFFE04) = (u32)0xE59FF018; *((vu32*)0x02FFFE24) = (u32)0x02FFFE04; - resetARM7(0x06000000); + resetARM7(0x06008000); swiSoftReset(); return true; @@ -507,7 +495,7 @@ int runNdsFile (const char* filename, int argc, const char** argv, bool dldiPatc filename = argv[0]; } - bool havedsiSD = (access("sd:/", F_OK) == 0); + const bool havedsiSD = (access("sd:/", F_OK) == 0); if (REG_SCFG_EXT != 0 && havedsiSD) { // Check for Unlaunch @@ -526,7 +514,9 @@ int runNdsFile (const char* filename, int argc, const char** argv, bool dldiPatc bool loadFromRam = runNds9(filename, dsModeSwitch); + #ifndef _NO_BOOTSTUB_ installBootStub(havedsiSD); + #endif return runNds (load_bin, load_bin_size, st.st_ino, true, (dldiPatchNds && memcmp(io_dldi_data->friendlyName, "Default", 7) != 0), loadFromRam, filename, argc, argv, clearMasterBright, dsModeSwitch, lockScfg, boostCpu, boostVram, tscTgds, language); } @@ -551,34 +541,31 @@ int runNdsFile (const char* filename, int argc, const char** argv, bool dldiPatc .word 0 */ -bool installBootStub(bool havedsiSD) { #ifndef _NO_BOOTSTUB_ +void installBootStub(bool havedsiSD) { + static bool installed = false; + if (installed) return; + extern char *fake_heap_end; struct __bootstub *bootstub = (struct __bootstub *)fake_heap_end; u32 *bootloader = (u32*)(fake_heap_end+bootstub_bin_size); - memcpy(bootstub,bootstub_bin,bootstub_bin_size); - memcpy(bootloader,load_bin,load_bin_size); - bool ret = false; + tonccpy(bootstub,bootstub_bin,bootstub_bin_size); + tonccpy(bootloader,load_bin,load_bin_size); bootloader[8] = isDSiMode(); if (havedsiSD) { - ret = true; bootloader[3] = 0; // don't dldi patch bootloader[7] = 1; // use internal dsi SD code } else { - ret = dldiPatchLoader((data_t*)bootloader, load_bin_size,false); + dldiPatchLoader (); } bootstub->arm9reboot = (VoidFn)(((u32)bootstub->arm9reboot)+fake_heap_end); bootstub->arm7reboot = (VoidFn)(((u32)bootstub->arm7reboot)+fake_heap_end); bootstub->bootsize = load_bin_size; DC_FlushAll(); - - return ret; -#else - return true; -#endif - + installed = true; } +#endif