From f0c7079e08b0d81bdf2ee1e380eca78b273260a0 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Sat, 9 Apr 2016 21:50:50 +0200 Subject: [PATCH] Added virtual memory drive --- source/fs.c | 11 +++- source/godmode.c | 2 +- source/nand/nand.c | 2 +- source/nand/nand.h | 2 +- source/nand/virtual.c | 132 ++++++++++++++++++++++++++---------------- source/nand/virtual.h | 7 ++- 6 files changed, 97 insertions(+), 59 deletions(-) diff --git a/source/fs.c b/source/fs.c index 82ef6a1..a536c5d 100644 --- a/source/fs.c +++ b/source/fs.c @@ -8,7 +8,7 @@ #define MAIN_BUFFER_SIZE (0x100000) // must be multiple of 0x200 #define NORM_FS 10 -#define VIRT_FS 3 +#define VIRT_FS 4 // don't use this area for anything else! static FATFS* fs = (FATFS*)0x20316000; @@ -78,7 +78,8 @@ bool CheckWritePermissions(const char* path) { int pdrv = PathToNumFS(path); if (pdrv < 0) { if (IsVirtualPath(path)) // this is a hack, but okay for now - pdrv = (IsVirtualPath(path) == VRT_SYSNAND) ? 1 : 4; + pdrv = (IsVirtualPath(path) == VRT_MEMORY) ? 10 : + (IsVirtualPath(path) == VRT_SYSNAND) ? 1 : 4; else return false; } @@ -98,6 +99,9 @@ bool CheckWritePermissions(const char* path) { if (ShowPrompt(true, "Writing to the SD card is locked!\nUnlock it now?")) return SetWritePermissions(1); return false; + } else if (pdrv >= 10) { + ShowPrompt(false, "Writing to memory is forbidden!"); + return false; } return true; @@ -594,9 +598,10 @@ bool GetRootDirContentsWorker(DirStruct* contents) { "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", "SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL", + "MEMORY VIRTUAL" }; static const char* drvnum[] = { - "0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "S:", "E:", "I:" + "0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "S:", "E:", "I:", "M:" }; u32 n_entries = 0; diff --git a/source/godmode.c b/source/godmode.c index ba1f964..6b2f7b4 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -7,7 +7,7 @@ #include "virtual.h" #include "image.h" -#define VERSION "0.3.1" +#define VERSION "0.3.3" #define N_PANES 2 #define IMG_DRV "789I" diff --git a/source/nand/nand.c b/source/nand/nand.c index 80ec7f1..3d02f4d 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -251,7 +251,7 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n return 0; } -u8 CheckNandType(u32 nand_src) +u32 CheckNandType(u32 nand_src) { if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, nand_src) != 0) return 0; diff --git a/source/nand/nand.h b/source/nand/nand.h index d109956..a49909b 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -18,6 +18,6 @@ int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src); int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest); u64 GetNandSizeSectors(u32 src); -u8 CheckNandType(u32 src); +u32 CheckNandType(u32 src); bool InitEmuNandBase(void); diff --git a/source/nand/virtual.c b/source/nand/virtual.c index 42674af..248be9f 100644 --- a/source/nand/virtual.c +++ b/source/nand/virtual.c @@ -1,11 +1,16 @@ #include "virtual.h" +#include "platform.h" +#define VRT_ANYNAND (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND) #define VFLAG_ON_O3DS NAND_TYPE_O3DS #define VFLAG_ON_N3DS NAND_TYPE_N3DS #define VFLAG_ON_NO3DS NAND_TYPE_NO3DS #define VFLAG_ON_ALL (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS) +#define VFLAG_ON_MEMORY VRT_MEMORY #define VFLAG_NAND_SIZE (1<<31) +// see: http://3dbrew.org/wiki/Flash_Filesystem#NAND_structure +// see: http://3dbrew.org/wiki/Memory_layout#ARM9 VirtualFile virtualFileTemplates[] = { { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL }, { "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_ALL }, @@ -22,7 +27,15 @@ VirtualFile virtualFileTemplates[] = { { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS }, { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS }, { "sector0x96.bin" , 0x00012C00, 0x00000200, 0xFF, VFLAG_ON_ALL }, - { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_ALL } + { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_ALL }, + { "itcm.dmp" , 0x01FF8000, 0x00008000, 0xFF, VFLAG_ON_MEMORY }, + { "arm9internal.dmp" , 0x08000000, 0x00100000, 0xFF, VFLAG_ON_MEMORY }, + { "vram.dmp" , 0x18000000, 0x00600000, 0xFF, VFLAG_ON_MEMORY }, + { "dsp.dmp" , 0x1FF00000, 0x00080000, 0xFF, VFLAG_ON_MEMORY }, + { "axiwram.dmp" , 0x1FF80000, 0x00080000, 0xFF, VFLAG_ON_MEMORY }, + { "fcram.dmp" , 0x20000000, 0x08000000, 0xFF, VFLAG_ON_MEMORY }, + { "dtcm.dmp" , 0xFFFF0000, 0x00004000, 0xFF, VFLAG_ON_MEMORY }, + { "bootrom_unp.dmp" , 0xFFFF0000, 0x00008000, 0xFF, VFLAG_ON_MEMORY } }; u32 IsVirtualPath(const char* path) { @@ -33,44 +46,45 @@ u32 IsVirtualPath(const char* path) { return VRT_EMUNAND; else if (strncmp(path, "I:/", (plen >= 3) ? 3 : 2) == 0) return VRT_IMGNAND; + else if (strncmp(path, "M:/", (plen >= 3) ? 3 : 2) == 0) + return VRT_MEMORY; return 0; } bool CheckVirtualPath(const char* path) { - u32 vp_nand = IsVirtualPath(path); - if ((vp_nand == VRT_EMUNAND) || (vp_nand == VRT_IMGNAND)) { - return GetNandSizeSectors(vp_nand); + u32 virtual_src = IsVirtualPath(path); + if ((virtual_src == VRT_EMUNAND) || (virtual_src == VRT_IMGNAND)) { + return GetNandSizeSectors(virtual_src); } - return vp_nand; // this is safe for SysNAND because we re-check for slot0x05 crypto + return virtual_src; // this is safe for SysNAND & memory } bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) { char* fname = strchr(path, '/'); - u8 nand_src = 0; - u8 nand_type = 0; + u32 virtual_src = 0; + u32 virtual_type = 0; // fix the name if (!fname) return false; fname++; // check path vailidity - nand_src = IsVirtualPath(path); - if (!nand_src || (fname - path != 3)) + virtual_src = IsVirtualPath(path); + if (!virtual_src || (fname - path != 3)) return false; // check NAND type - nand_type = CheckNandType(nand_src); + virtual_type = (virtual_src & VRT_ANYNAND) ? CheckNandType(virtual_src) : virtual_src; // parse the template list, get the correct one u32 n_templates = sizeof(virtualFileTemplates) / sizeof(VirtualFile); VirtualFile* curr_template = NULL; for (u32 i = 0; i < n_templates; i++) { - curr_template = &virtualFileTemplates[i]; - if ((curr_template->flags & nand_type) && (strncasecmp(fname, curr_template->name, 32) == 0)) - break; - else if (size && (curr_template->size == size)) //search by size should be a last resort solution - break; + curr_template = &virtualFileTemplates[i]; + if ((curr_template->flags & virtual_type) && ((strncasecmp(fname, curr_template->name, 32) == 0) || + (size && (curr_template->size == size)))) // search by size should be a last resort solution + break; curr_template = NULL; } if (!curr_template) return false; @@ -82,11 +96,11 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) return false; // keyslot 0x05 not properly set up if (vfile->flags & VFLAG_NAND_SIZE) { - if ((nand_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src))) + if ((virtual_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(virtual_src))) return false; // EmuNAND/IMGNAND is too small vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200; } - vfile->flags |= nand_src; + vfile->flags |= virtual_src; return true; } @@ -99,37 +113,45 @@ int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, else if ((offset + count) > vfile->size) count = vfile->size - offset; if (bytes_read) *bytes_read = count; - if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case - // simple wrapper function for ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src) - return ReadNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, - vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); - } else { // nonaligned data -> -___- - u8 l_buffer[0x200]; - u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); - u32 keyslot = vfile->keyslot; - int errorcode = 0; - if (foffset % 0x200) { // handle misaligned offset - u32 offset_fix = 0x200 - (foffset % 0x200); - errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_src); - if (errorcode != 0) return errorcode; - memcpy(buffer, l_buffer + 0x200 - offset_fix, min(offset_fix, count)); - if (count <= offset_fix) return 0; - foffset += offset_fix; - buffer += offset_fix; - count -= offset_fix; - } // foffset is now aligned and part of the data is read - if (count >= 0x200) { // otherwise this is misaligned and will be handled below - errorcode = ReadNandSectors(buffer, foffset / 0x200, count / 0x200, keyslot, nand_src); - if (errorcode != 0) return errorcode; + + if (vfile->flags & VFLAG_ON_ALL) { + if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case + // simple wrapper function for ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src) + return ReadNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, + vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); + } else { // nonaligned data -> -___- + u8 l_buffer[0x200]; + u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); + u32 keyslot = vfile->keyslot; + int errorcode = 0; + if (foffset % 0x200) { // handle misaligned offset + u32 offset_fix = 0x200 - (foffset % 0x200); + errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_src); + if (errorcode != 0) return errorcode; + memcpy(buffer, l_buffer + 0x200 - offset_fix, min(offset_fix, count)); + if (count <= offset_fix) return 0; + foffset += offset_fix; + buffer += offset_fix; + count -= offset_fix; + } // foffset is now aligned and part of the data is read + if (count >= 0x200) { // otherwise this is misaligned and will be handled below + errorcode = ReadNandSectors(buffer, foffset / 0x200, count / 0x200, keyslot, nand_src); + if (errorcode != 0) return errorcode; + } + if (count % 0x200) { // handle misaligned count + u32 count_fix = count % 0x200; + errorcode = ReadNandSectors(l_buffer, (foffset + count) / 0x200, 1, keyslot, nand_src); + if (errorcode != 0) return errorcode; + memcpy(buffer + count - count_fix, l_buffer, count_fix); + } + return errorcode; } - if (count % 0x200) { // handle misaligned count - u32 count_fix = count % 0x200; - errorcode = ReadNandSectors(l_buffer, (foffset + count) / 0x200, 1, keyslot, nand_src); - if (errorcode != 0) return errorcode; - memcpy(buffer + count - count_fix, l_buffer, count_fix); - } - return errorcode; + } else if (vfile->flags & VFLAG_ON_MEMORY) { + memcpy(buffer, (u8*) foffset, count); + return 0; } + + return -1; } int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written) @@ -140,9 +162,17 @@ int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 else if ((offset + count) > vfile->size) count = vfile->size - offset; if (bytes_written) *bytes_written = count; - if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case - // simple wrapper function for WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest) - return WriteNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, - vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); - } else return -1; // misaligned data -> not implemented (!!!) + + if (vfile->flags & VFLAG_ON_ALL) { + if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case + // simple wrapper function for WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest) + return WriteNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, + vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); + } else return -1; // misaligned data -> not implemented (!!!) + } else if (vfile->flags & VFLAG_ON_MEMORY) { + memcpy((u8*) foffset, buffer, count); + return 0; + } + + return -1; } diff --git a/source/nand/virtual.h b/source/nand/virtual.h index 3c2d481..79e142c 100644 --- a/source/nand/virtual.h +++ b/source/nand/virtual.h @@ -6,10 +6,13 @@ #define VRT_SYSNAND NAND_SYSNAND #define VRT_EMUNAND NAND_EMUNAND #define VRT_IMGNAND NAND_IMGNAND +#define VRT_MEMORY (1<<10) static const char* virtualFileList[] = { // must have a match in virtualFileTemplates[] - "twln.bin", "twlp.bin", "agbsave.bin", "firm0.bin", "firm1.bin", "ctrnand_fat.bin", "ctrnand_full.bin", - "nand.bin", "nand_minsize.bin", "nand_hdr.bin", "sector0x96.bin" + "twln.bin", "twlp.bin", "agbsave.bin", "firm0.bin", "firm1.bin", "ctrnand_fat.bin", + "ctrnand_full.bin", "nand.bin", "nand_minsize.bin", "nand_hdr.bin", "sector0x96.bin", + "itcm.dmp", "arm9internal.dmp", "vram.dmp", "dsp.dmp", "axiwram.dmp", "fcram.dmp", + "dtcm.dmp", "bootrom_unp.dmp" }; static const u32 virtualFileList_size = sizeof(virtualFileList) / sizeof(char*);