diff --git a/source/virtual/virtual.c b/source/virtual/virtual.c index fd3408d..418504c 100644 --- a/source/virtual/virtual.c +++ b/source/virtual/virtual.c @@ -1,121 +1,52 @@ #include "virtual.h" -#include "platform.h" +#include "vnand.h" +#include "vmem.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_NAND (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS) -#define VFLAG_ON_MEMORY VRT_MEMORY -#define VFLAG_NEEDS_OTP (1<<29) -#define VFLAG_N3DS_ONLY (1<<30) -#define VFLAG_NAND_SIZE (1<<31) +typedef struct { + char drv_letter; + u32 virtual_src; +} __attribute__((packed)) VirtualDrive; -// 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_NAND }, - { "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_NAND }, - { "agbsave.bin" , 0x0B100000, 0x00030000, 0x07, VFLAG_ON_NAND }, - { "firm0.bin" , 0x0B130000, 0x00400000, 0x06, VFLAG_ON_NAND | VFLAG_A9LH_AREA}, - { "firm1.bin" , 0x0B530000, 0x00400000, 0x06, VFLAG_ON_NAND | VFLAG_A9LH_AREA}, - { "ctrnand_fat.bin" , 0x0B95CA00, 0x2F3E3600, 0x04, VFLAG_ON_O3DS }, - { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x05, VFLAG_ON_N3DS }, - { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x04, VFLAG_ON_NO3DS }, - { "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS }, - { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS }, - { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS }, - { "sector0x96.bin" , 0x00012C00, 0x00000200, 0x11, VFLAG_ON_NAND | VFLAG_NEEDS_OTP | VFLAG_A9LH_AREA }, - { "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_NAND | VFLAG_NAND_SIZE | VFLAG_A9LH_AREA }, - { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS | VFLAG_A9LH_AREA }, - { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS | VFLAG_A9LH_AREA }, - { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_NAND | VFLAG_A9LH_AREA }, - { "twlmbr.bin" , 0x000001BE, 0x00000042, 0x03, VFLAG_ON_NAND | VFLAG_A9LH_AREA }, - { "itcm.mem" , 0x01FF8000, 0x00008000, 0xFF, VFLAG_ON_MEMORY }, - { "arm9.mem" , 0x08000000, 0x00100000, 0xFF, VFLAG_ON_MEMORY }, - { "arm9ext.mem" , 0x08010000, 0x00080000, 0xFF, VFLAG_ON_MEMORY | VFLAG_N3DS_ONLY }, - { "vram.mem" , 0x18000000, 0x00600000, 0xFF, VFLAG_ON_MEMORY }, - { "dsp.mem" , 0x1FF00000, 0x00080000, 0xFF, VFLAG_ON_MEMORY }, - { "axiwram.mem" , 0x1FF80000, 0x00080000, 0xFF, VFLAG_ON_MEMORY }, - { "fcram.mem" , 0x20000000, 0x08000000, 0xFF, VFLAG_ON_MEMORY }, - { "fcramext.mem" , 0x28000000, 0x08000000, 0xFF, VFLAG_ON_MEMORY | VFLAG_N3DS_ONLY }, - { "dtcm.mem" , 0x30008000, 0x00004000, 0xFF, VFLAG_ON_MEMORY }, - // { "otp.mem" , 0x10012000, 0x00000108, 0xFF, VFLAG_ON_MEMORY }, - // { "bootrom.mem" , 0xFFFF0000, 0x00010000, 0xFF, VFLAG_ON_MEMORY }, - { "bootrom_unp.mem" , 0xFFFF0000, 0x00008000, 0xFF, VFLAG_ON_MEMORY } -}; +static const VirtualDrive virtualDrives[] = { {'S', VRT_SYSNAND}, {'E', VRT_EMUNAND}, {'I', VRT_IMGNAND}, {'M', VRT_MEMORY} }; u32 GetVirtualSource(const char* path) { - u32 plen = strnlen(path, 16); - if (strncmp(path, "S:/", (plen >= 3) ? 3 : 2) == 0) - return VRT_SYSNAND; - else if (strncmp(path, "E:/", (plen >= 3) ? 3 : 2) == 0) - 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; + // check path validity + if ((strnlen(path, 16) < 2) || (path[1] != ':') || ((path[2] != '/') && (path[2] != '\0'))) + return 0; + // search for virtual source + for (u32 i = 0; i < (sizeof(virtualDrives) / sizeof(VirtualDrive)); i++) + if (*path == virtualDrives[i].drv_letter) return virtualDrives[i].virtual_src; return 0; } bool CheckVirtualDrive(const char* path) { u32 virtual_src = GetVirtualSource(path); - if ((virtual_src == VRT_EMUNAND) || (virtual_src == VRT_IMGNAND)) { - return GetNandSizeSectors(virtual_src); - } + if (virtual_src & (VRT_EMUNAND|VRT_IMGNAND)) + return CheckVNandDrive(virtual_src); // check virtual NAND drive for EmuNAND / ImgNAND return virtual_src; // this is safe for SysNAND & memory } bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) { + // get / fix the name char* fname = strchr(path, '/'); - u32 virtual_src = 0; - u32 virtual_type = 0; - - // fix the name if (!fname) return false; fname++; - // check path vailidity + // check path validity / get virtual source + u32 virtual_src = 0; virtual_src = GetVirtualSource(path); if (!virtual_src || (fname - path != 3)) return false; - // check virtual type - if (virtual_src & VRT_ANYNAND) { - virtual_type = CheckNandType(virtual_src); // workaround if this comes up with no result - if (!virtual_type) virtual_type = (GetUnitPlatform() == PLATFORM_3DS) ? NAND_TYPE_O3DS : NAND_TYPE_N3DS; - } else virtual_type = virtual_src; + // get virtual file struct from appropriate function + if (virtual_src & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) { + if (!FindVNandFile(vfile, virtual_src, fname, size)) return false; + } else if (virtual_src & VRT_MEMORY) { + if (!FindVMemFile(vfile, fname, size)) return false; + } else return false; - // 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 & 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; - - // copy current template to vfile - memcpy(vfile, curr_template, sizeof(VirtualFile)); - - // process special flags - if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) - return false; // keyslot 0x05 not properly set up - if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto()) - return false; // sector 0x96 crypto not set up - if (!(virtual_src & VRT_SYSNAND) || (*(vu32*) 0x101401C0)) - vfile->flags &= ~VFLAG_A9LH_AREA; // flag is meaningless outside of A9LH / SysNAND - if ((vfile->flags & VFLAG_N3DS_ONLY) && (GetUnitPlatform() != PLATFORM_N3DS)) - return false; // this is not on O3DS consoles - if (vfile->flags & VFLAG_NAND_SIZE) { - if ((virtual_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(virtual_src))) - return false; // EmuNAND/ImgNAND is too small - vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200; - } + // add the virtual source to the virtual file flags vfile->flags |= virtual_src; return true; @@ -123,47 +54,17 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read) { - u32 foffset = vfile->offset + offset; + // basic check of offset / count if (offset >= vfile->size) return 0; else if ((offset + count) > vfile->size) count = vfile->size - offset; if (bytes_read) *bytes_read = count; - if (vfile->flags & VFLAG_ON_NAND) { - u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); - u32 keyslot = vfile->keyslot; - 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, keyslot, nand_src); - } else { // misaligned data -> -___- - u8 l_buffer[0x200]; - 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; - } - } else if (vfile->flags & VFLAG_ON_MEMORY) { - memcpy(buffer, (u8*) foffset, count); - return 0; + if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) { + return ReadVNandFile(vfile, buffer, offset, count); + } else if (vfile->flags & VRT_MEMORY) { + return ReadVMemFile(vfile, buffer, offset, count); } return -1; @@ -171,51 +72,17 @@ int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written) { - u32 foffset = vfile->offset + offset; + // basic check of offset / count if (offset >= vfile->size) return 0; else if ((offset + count) > vfile->size) count = vfile->size - offset; if (bytes_written) *bytes_written = count; - if (vfile->flags & VFLAG_ON_NAND) { - u32 nand_dst = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); - u32 keyslot = vfile->keyslot; - 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, keyslot, nand_dst); - } else { // misaligned data -> -___- - u8 l_buffer[0x200]; - int errorcode = 0; - if (foffset % 0x200) { // handle misaligned offset - u32 offset_fix = 0x200 - (foffset % 0x200); - errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_dst); - if (errorcode != 0) return errorcode; - memcpy(l_buffer + 0x200 - offset_fix, buffer, min(offset_fix, count)); - errorcode = WriteNandSectors((const u8*) l_buffer, foffset / 0x200, 1, keyslot, nand_dst); - if (errorcode != 0) return errorcode; - 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 written - if (count >= 0x200) { // otherwise this is misaligned and will be handled below - errorcode = WriteNandSectors(buffer, foffset / 0x200, count / 0x200, keyslot, nand_dst); - 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_dst); - if (errorcode != 0) return errorcode; - memcpy(l_buffer, buffer + count - count_fix, count_fix); - errorcode = WriteNandSectors((const u8*) l_buffer, (foffset + count) / 0x200, 1, keyslot, nand_dst); - if (errorcode != 0) return errorcode; - } - return errorcode; - } - } else if (vfile->flags & VFLAG_ON_MEMORY) { - memcpy((u8*) foffset, buffer, count); - return 0; + if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) { + return WriteVNandFile(vfile, buffer, offset, count); + } else if (vfile->flags & VRT_MEMORY) { + return WriteVMemFile(vfile, buffer, offset, count); } return -1; diff --git a/source/virtual/virtual.h b/source/virtual/virtual.h index 1f61b96..043a323 100644 --- a/source/virtual/virtual.h +++ b/source/virtual/virtual.h @@ -18,6 +18,11 @@ static const char* virtualFileList[] = { // must have a match in virtualFileTemp }; static const u32 virtualFileList_size = sizeof(virtualFileList) / sizeof(char*); +// virtual file flag (subject to change): +// bits 0...9 : reserved for NAND virtual sources and info +// bits 10...19: reserved for other virtual sources +// bits 20...24: reserved for external flags +// bits 24...31: reserved for internal flags (different per source) typedef struct { const char name[32]; u32 offset; // must be a multiple of 0x200 diff --git a/source/virtual/vmem.c b/source/virtual/vmem.c new file mode 100644 index 0000000..ca38a38 --- /dev/null +++ b/source/virtual/vmem.c @@ -0,0 +1,55 @@ +#include "vmem.h" +#include "platform.h" + +#define VFLAG_N3DS_ONLY (1<<31) + +// see: http://3dbrew.org/wiki/Memory_layout#ARM9 +static const VirtualFile vMemFileTemplates[] = { + { "itcm.mem" , 0x01FF8000, 0x00008000, 0xFF, 0 }, + { "arm9.mem" , 0x08000000, 0x00100000, 0xFF, 0 }, + { "arm9ext.mem" , 0x08010000, 0x00080000, 0xFF, VFLAG_N3DS_ONLY }, + { "vram.mem" , 0x18000000, 0x00600000, 0xFF, 0 }, + { "dsp.mem" , 0x1FF00000, 0x00080000, 0xFF, 0 }, + { "axiwram.mem" , 0x1FF80000, 0x00080000, 0xFF, 0 }, + { "fcram.mem" , 0x20000000, 0x08000000, 0xFF, 0 }, + { "fcramext.mem" , 0x28000000, 0x08000000, 0xFF, VFLAG_N3DS_ONLY }, + { "dtcm.mem" , 0x30008000, 0x00004000, 0xFF, 0 }, + // { "otp.mem" , 0x10012000, 0x00000108, 0xFF, 0 }, + // { "bootrom.mem" , 0xFFFF0000, 0x00010000, 0xFF, 0 }, + { "bootrom_unp.mem" , 0xFFFF0000, 0x00008000, 0xFF, 0 } +}; + +bool FindVMemFile(VirtualFile* vfile, const char* name, u32 size) { + // parse the template list, get the correct one + u32 n_templates = sizeof(vMemFileTemplates) / sizeof(VirtualFile); + const VirtualFile* curr_template = NULL; + for (u32 i = 0; i < n_templates; i++) { + curr_template = &vMemFileTemplates[i]; + if (((strncasecmp(name, 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; + + // copy current template to vfile + memcpy(vfile, curr_template, sizeof(VirtualFile)); + + // process special flag + if ((vfile->flags & VFLAG_N3DS_ONLY) && (GetUnitPlatform() != PLATFORM_N3DS)) + return false; // this is not on O3DS consoles + + return true; +} + +int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { + u32 foffset = vfile->offset + offset; + memcpy(buffer, (u8*) foffset, count); + return 0; +} + +int WriteVMemFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count) { + u32 foffset = vfile->offset + offset; + memcpy((u8*) foffset, buffer, count); + return 0; +} diff --git a/source/virtual/vmem.h b/source/virtual/vmem.h new file mode 100644 index 0000000..8e3f3c0 --- /dev/null +++ b/source/virtual/vmem.h @@ -0,0 +1,8 @@ +#pragma once + +#include "common.h" +#include "virtual.h" + +bool FindVMemFile(VirtualFile* vfile, const char* name, u32 size); +int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count); +int WriteVMemFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count); diff --git a/source/virtual/vnand.c b/source/virtual/vnand.c new file mode 100644 index 0000000..d0f4aec --- /dev/null +++ b/source/virtual/vnand.c @@ -0,0 +1,146 @@ +#include "vnand.h" +#include "nand.h" +#include "platform.h" + +#define VFLAG_ON_O3DS NAND_TYPE_O3DS +#define VFLAG_ON_N3DS NAND_TYPE_N3DS +#define VFLAG_ON_NO3DS NAND_TYPE_NO3DS +#define VFLAG_ON_NAND (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS) +#define VFLAG_NEEDS_OTP (1<<30) +#define VFLAG_NAND_SIZE (1<<31) + +// see: http://3dbrew.org/wiki/Flash_Filesystem#NAND_structure +static const VirtualFile vNandFileTemplates[] = { + { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_NAND }, + { "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_NAND }, + { "agbsave.bin" , 0x0B100000, 0x00030000, 0x07, VFLAG_ON_NAND }, + { "firm0.bin" , 0x0B130000, 0x00400000, 0x06, VFLAG_ON_NAND | VFLAG_A9LH_AREA}, + { "firm1.bin" , 0x0B530000, 0x00400000, 0x06, VFLAG_ON_NAND | VFLAG_A9LH_AREA}, + { "ctrnand_fat.bin" , 0x0B95CA00, 0x2F3E3600, 0x04, VFLAG_ON_O3DS }, + { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x05, VFLAG_ON_N3DS }, + { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x04, VFLAG_ON_NO3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS }, + { "sector0x96.bin" , 0x00012C00, 0x00000200, 0x11, VFLAG_ON_NAND | VFLAG_NEEDS_OTP | VFLAG_A9LH_AREA }, + { "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_NAND | VFLAG_NAND_SIZE | VFLAG_A9LH_AREA }, + { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS | VFLAG_A9LH_AREA }, + { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS | VFLAG_A9LH_AREA }, + { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_NAND | VFLAG_A9LH_AREA }, + { "twlmbr.bin" , 0x000001BE, 0x00000042, 0x03, VFLAG_ON_NAND | VFLAG_A9LH_AREA } +}; + +bool CheckVNandDrive(u32 nand_src) { + return GetNandSizeSectors(nand_src); +} + +bool FindVNandFile(VirtualFile* vfile, u32 nand_src, const char* name, u32 size) { + // get virtual type (O3DS/N3DS/NO3DS) + u32 virtual_type = CheckNandType(nand_src); + // workaround if CheckNandType() comes up with no result (empty EmuNAND) + if (!virtual_type) virtual_type = (GetUnitPlatform() == PLATFORM_3DS) ? NAND_TYPE_O3DS : NAND_TYPE_N3DS; + + // parse the template list, get the correct one + u32 n_templates = sizeof(vNandFileTemplates) / sizeof(VirtualFile); + const VirtualFile* curr_template = NULL; + for (u32 i = 0; i < n_templates; i++) { + curr_template = &vNandFileTemplates[i]; + if ((curr_template->flags & virtual_type) && ((strncasecmp(name, 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; + + // copy current template to vfile + memcpy(vfile, curr_template, sizeof(VirtualFile)); + + // process special flags + if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) + return false; // keyslot 0x05 not properly set up + if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto()) + return false; // sector 0x96 crypto not set up + if (!(nand_src & VRT_SYSNAND) || (*(vu32*) 0x101401C0)) + vfile->flags &= ~VFLAG_A9LH_AREA; // flag is meaningless outside of A9LH / SysNAND + if (vfile->flags & VFLAG_NAND_SIZE) { + if ((nand_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src))) + return false; // EmuNAND/ImgNAND is too small + vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200; + } + + return true; +} + +int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { + u32 foffset = vfile->offset + offset; + u32 nand_src = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); + u32 keyslot = vfile->keyslot; + + 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, keyslot, nand_src); + } else { // misaligned data -> -___- + u8 l_buffer[0x200]; + 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; + } +} + +int WriteVNandFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count) { + u32 foffset = vfile->offset + offset; + u32 nand_dst = vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND); + u32 keyslot = vfile->keyslot; + + 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, keyslot, nand_dst); + } else { // misaligned data -> -___- + u8 l_buffer[0x200]; + int errorcode = 0; + if (foffset % 0x200) { // handle misaligned offset + u32 offset_fix = 0x200 - (foffset % 0x200); + errorcode = ReadNandSectors(l_buffer, foffset / 0x200, 1, keyslot, nand_dst); + if (errorcode != 0) return errorcode; + memcpy(l_buffer + 0x200 - offset_fix, buffer, min(offset_fix, count)); + errorcode = WriteNandSectors((const u8*) l_buffer, foffset / 0x200, 1, keyslot, nand_dst); + if (errorcode != 0) return errorcode; + 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 written + if (count >= 0x200) { // otherwise this is misaligned and will be handled below + errorcode = WriteNandSectors(buffer, foffset / 0x200, count / 0x200, keyslot, nand_dst); + 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_dst); + if (errorcode != 0) return errorcode; + memcpy(l_buffer, buffer + count - count_fix, count_fix); + errorcode = WriteNandSectors((const u8*) l_buffer, (foffset + count) / 0x200, 1, keyslot, nand_dst); + if (errorcode != 0) return errorcode; + } + return errorcode; + } +} diff --git a/source/virtual/vnand.h b/source/virtual/vnand.h new file mode 100644 index 0000000..c11ddc6 --- /dev/null +++ b/source/virtual/vnand.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common.h" +#include "virtual.h" + +bool CheckVNandDrive(u32 nand_src); +bool FindVNandFile(VirtualFile* vfile, u32 nand_src, const char* name, u32 size); +int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count); +int WriteVNandFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);