Added virtual memory drive

This commit is contained in:
d0k3 2016-04-09 21:50:50 +02:00
parent cdc3cf6f27
commit f0c7079e08
6 changed files with 97 additions and 59 deletions

View File

@ -8,7 +8,7 @@
#define MAIN_BUFFER_SIZE (0x100000) // must be multiple of 0x200 #define MAIN_BUFFER_SIZE (0x100000) // must be multiple of 0x200
#define NORM_FS 10 #define NORM_FS 10
#define VIRT_FS 3 #define VIRT_FS 4
// don't use this area for anything else! // don't use this area for anything else!
static FATFS* fs = (FATFS*)0x20316000; static FATFS* fs = (FATFS*)0x20316000;
@ -78,7 +78,8 @@ bool CheckWritePermissions(const char* path) {
int pdrv = PathToNumFS(path); int pdrv = PathToNumFS(path);
if (pdrv < 0) { if (pdrv < 0) {
if (IsVirtualPath(path)) // this is a hack, but okay for now 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; 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?")) if (ShowPrompt(true, "Writing to the SD card is locked!\nUnlock it now?"))
return SetWritePermissions(1); return SetWritePermissions(1);
return false; return false;
} else if (pdrv >= 10) {
ShowPrompt(false, "Writing to memory is forbidden!");
return false;
} }
return true; return true;
@ -594,9 +598,10 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
"EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP",
"IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", "IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP",
"SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL", "SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL",
"MEMORY VIRTUAL"
}; };
static const char* drvnum[] = { 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; u32 n_entries = 0;

View File

@ -7,7 +7,7 @@
#include "virtual.h" #include "virtual.h"
#include "image.h" #include "image.h"
#define VERSION "0.3.1" #define VERSION "0.3.3"
#define N_PANES 2 #define N_PANES 2
#define IMG_DRV "789I" #define IMG_DRV "789I"

View File

@ -251,7 +251,7 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n
return 0; return 0;
} }
u8 CheckNandType(u32 nand_src) u32 CheckNandType(u32 nand_src)
{ {
if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, nand_src) != 0) if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, nand_src) != 0)
return 0; return 0;

View File

@ -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); int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest);
u64 GetNandSizeSectors(u32 src); u64 GetNandSizeSectors(u32 src);
u8 CheckNandType(u32 src); u32 CheckNandType(u32 src);
bool InitEmuNandBase(void); bool InitEmuNandBase(void);

View File

@ -1,11 +1,16 @@
#include "virtual.h" #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_O3DS NAND_TYPE_O3DS
#define VFLAG_ON_N3DS NAND_TYPE_N3DS #define VFLAG_ON_N3DS NAND_TYPE_N3DS
#define VFLAG_ON_NO3DS NAND_TYPE_NO3DS #define VFLAG_ON_NO3DS NAND_TYPE_NO3DS
#define VFLAG_ON_ALL (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_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) #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[] = { VirtualFile virtualFileTemplates[] = {
{ "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL }, { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL },
{ "twlp.bin" , 0x09011A00, 0x020B6600, 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, 0x3AF00000, 0xFF, VFLAG_ON_O3DS },
{ "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS }, { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS },
{ "sector0x96.bin" , 0x00012C00, 0x00000200, 0xFF, VFLAG_ON_ALL }, { "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) { u32 IsVirtualPath(const char* path) {
@ -33,44 +46,45 @@ u32 IsVirtualPath(const char* path) {
return VRT_EMUNAND; return VRT_EMUNAND;
else if (strncmp(path, "I:/", (plen >= 3) ? 3 : 2) == 0) else if (strncmp(path, "I:/", (plen >= 3) ? 3 : 2) == 0)
return VRT_IMGNAND; return VRT_IMGNAND;
else if (strncmp(path, "M:/", (plen >= 3) ? 3 : 2) == 0)
return VRT_MEMORY;
return 0; return 0;
} }
bool CheckVirtualPath(const char* path) { bool CheckVirtualPath(const char* path) {
u32 vp_nand = IsVirtualPath(path); u32 virtual_src = IsVirtualPath(path);
if ((vp_nand == VRT_EMUNAND) || (vp_nand == VRT_IMGNAND)) { if ((virtual_src == VRT_EMUNAND) || (virtual_src == VRT_IMGNAND)) {
return GetNandSizeSectors(vp_nand); 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) bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size)
{ {
char* fname = strchr(path, '/'); char* fname = strchr(path, '/');
u8 nand_src = 0; u32 virtual_src = 0;
u8 nand_type = 0; u32 virtual_type = 0;
// fix the name // fix the name
if (!fname) return false; if (!fname) return false;
fname++; fname++;
// check path vailidity // check path vailidity
nand_src = IsVirtualPath(path); virtual_src = IsVirtualPath(path);
if (!nand_src || (fname - path != 3)) if (!virtual_src || (fname - path != 3))
return false; return false;
// check NAND type // 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 // parse the template list, get the correct one
u32 n_templates = sizeof(virtualFileTemplates) / sizeof(VirtualFile); u32 n_templates = sizeof(virtualFileTemplates) / sizeof(VirtualFile);
VirtualFile* curr_template = NULL; VirtualFile* curr_template = NULL;
for (u32 i = 0; i < n_templates; i++) { for (u32 i = 0; i < n_templates; i++) {
curr_template = &virtualFileTemplates[i]; curr_template = &virtualFileTemplates[i];
if ((curr_template->flags & nand_type) && (strncasecmp(fname, curr_template->name, 32) == 0)) if ((curr_template->flags & virtual_type) && ((strncasecmp(fname, curr_template->name, 32) == 0) ||
break; (size && (curr_template->size == size)))) // search by size should be a last resort solution
else if (size && (curr_template->size == size)) //search by size should be a last resort solution break;
break;
curr_template = NULL; curr_template = NULL;
} }
if (!curr_template) return false; if (!curr_template) return false;
@ -82,11 +96,11 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size)
if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto())
return false; // keyslot 0x05 not properly set up return false; // keyslot 0x05 not properly set up
if (vfile->flags & VFLAG_NAND_SIZE) { 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 return false; // EmuNAND/IMGNAND is too small
vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200; vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200;
} }
vfile->flags |= nand_src; vfile->flags |= virtual_src;
return true; return true;
} }
@ -99,37 +113,45 @@ int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count,
else if ((offset + count) > vfile->size) else if ((offset + count) > vfile->size)
count = vfile->size - offset; count = vfile->size - offset;
if (bytes_read) *bytes_read = count; 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) if (vfile->flags & VFLAG_ON_ALL) {
return ReadNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case
vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); // simple wrapper function for ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src)
} else { // nonaligned data -> -___- return ReadNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot,
u8 l_buffer[0x200]; vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND));
u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); } else { // nonaligned data -> -___-
u32 keyslot = vfile->keyslot; u8 l_buffer[0x200];
int errorcode = 0; u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND);
if (foffset % 0x200) { // handle misaligned offset u32 keyslot = vfile->keyslot;
u32 offset_fix = 0x200 - (foffset % 0x200); int errorcode = 0;
errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_src); if (foffset % 0x200) { // handle misaligned offset
if (errorcode != 0) return errorcode; u32 offset_fix = 0x200 - (foffset % 0x200);
memcpy(buffer, l_buffer + 0x200 - offset_fix, min(offset_fix, count)); errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_src);
if (count <= offset_fix) return 0; if (errorcode != 0) return errorcode;
foffset += offset_fix; memcpy(buffer, l_buffer + 0x200 - offset_fix, min(offset_fix, count));
buffer += offset_fix; if (count <= offset_fix) return 0;
count -= offset_fix; foffset += offset_fix;
} // foffset is now aligned and part of the data is read buffer += offset_fix;
if (count >= 0x200) { // otherwise this is misaligned and will be handled below count -= offset_fix;
errorcode = ReadNandSectors(buffer, foffset / 0x200, count / 0x200, keyslot, nand_src); } // foffset is now aligned and part of the data is read
if (errorcode != 0) return errorcode; 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 } else if (vfile->flags & VFLAG_ON_MEMORY) {
u32 count_fix = count % 0x200; memcpy(buffer, (u8*) foffset, count);
errorcode = ReadNandSectors(l_buffer, (foffset + count) / 0x200, 1, keyslot, nand_src); return 0;
if (errorcode != 0) return errorcode;
memcpy(buffer + count - count_fix, l_buffer, count_fix);
}
return errorcode;
} }
return -1;
} }
int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written) 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) else if ((offset + count) > vfile->size)
count = vfile->size - offset; count = vfile->size - offset;
if (bytes_written) *bytes_written = count; 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) if (vfile->flags & VFLAG_ON_ALL) {
return WriteNandSectors(buffer, foffset / 0x200, count / 0x200, vfile->keyslot, if (!(foffset % 0x200) && !(count % 0x200)) { // aligned data -> simple case
vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); // simple wrapper function for WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest)
} else return -1; // misaligned data -> not implemented (!!!) 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;
} }

View File

@ -6,10 +6,13 @@
#define VRT_SYSNAND NAND_SYSNAND #define VRT_SYSNAND NAND_SYSNAND
#define VRT_EMUNAND NAND_EMUNAND #define VRT_EMUNAND NAND_EMUNAND
#define VRT_IMGNAND NAND_IMGNAND #define VRT_IMGNAND NAND_IMGNAND
#define VRT_MEMORY (1<<10)
static const char* virtualFileList[] = { // must have a match in virtualFileTemplates[] 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", "twln.bin", "twlp.bin", "agbsave.bin", "firm0.bin", "firm1.bin", "ctrnand_fat.bin",
"nand.bin", "nand_minsize.bin", "nand_hdr.bin", "sector0x96.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*); static const u32 virtualFileList_size = sizeof(virtualFileList) / sizeof(char*);