diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index 67fb3f3..3419ca6 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -8,12 +8,15 @@ /*-----------------------------------------------------------------------*/ #include "diskio.h" /* FatFs lower layer API */ +#include "image.h" #include "nand.h" #include "sdmmc.h" -#define TYPE_SDCARD 0 -#define TYPE_SYSNAND 1 -#define TYPE_EMUNAND 2 +#define TYPE_SDCARD 0x00 +#define TYPE_SYSNAND NAND_SYSNAND +#define TYPE_EMUNAND NAND_EMUNAND +#define TYPE_IMGNAND NAND_IMGNAND +#define TYPE_IMAGE 0xFF #define SUBTYPE_CTRN 0 #define SUBTYPE_CTRN_N 1 @@ -33,7 +36,7 @@ typedef struct { BYTE keyslot; } SubtypeDesc; -FATpartition DriveInfo[7] = { +FATpartition DriveInfo[11] = { { TYPE_SDCARD, SUBTYPE_NONE }, // 0 - SDCARD { TYPE_SYSNAND, SUBTYPE_CTRN }, // 1 - SYSNAND CTRNAND { TYPE_SYSNAND, SUBTYPE_TWLN }, // 2 - SYSNAND TWLN @@ -41,6 +44,10 @@ FATpartition DriveInfo[7] = { { TYPE_EMUNAND, SUBTYPE_CTRN }, // 4 - EMUNAND CTRNAND { TYPE_EMUNAND, SUBTYPE_TWLN }, // 5 - EMUNAND TWLN { TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND TWLP + { TYPE_IMGNAND, SUBTYPE_CTRN }, // 7 - EMUNAND CTRNAND + { TYPE_IMGNAND, SUBTYPE_TWLN }, // 8 - EMUNAND TWLN + { TYPE_IMGNAND, SUBTYPE_TWLP }, // 9 - EMUNAND TWLP + { TYPE_IMAGE, SUBTYPE_NONE } // X - IMAGE }; SubtypeDesc SubTypes[5] = { @@ -51,8 +58,9 @@ SubtypeDesc SubTypes[5] = { { 0x04808D, 0x0105B3, 0x3 } // TWLP }; -static BYTE nand_type_sys = NAND_TYPE_UNK; -static BYTE nand_type_emu = NAND_TYPE_UNK; +static BYTE nand_type_sys = 0; +static BYTE nand_type_emu = 0; +static BYTE nand_type_img = 0; @@ -68,10 +76,10 @@ SubtypeDesc* get_subtype_desc( BYTE type = DriveInfo[pdrv].type; BYTE subtype = DriveInfo[pdrv].subtype; - if (type == TYPE_SDCARD) { + if (subtype == SUBTYPE_NONE) { return NULL; } else if (subtype == SUBTYPE_CTRN) { - BYTE nand_type = (type == TYPE_SYSNAND) ? nand_type_sys : nand_type_emu; + BYTE nand_type = (type == TYPE_SYSNAND) ? nand_type_sys : (type == TYPE_EMUNAND) ? nand_type_emu : nand_type_img; if (nand_type != NAND_TYPE_O3DS) subtype = (nand_type == NAND_TYPE_N3DS) ? SUBTYPE_CTRN_N : SUBTYPE_CTRN_NO; } @@ -108,9 +116,11 @@ DSTATUS disk_initialize ( if (!sdmmc_sdcard_init()) return RES_PARERR; } else if (pdrv < 4) { - nand_type_sys = CheckNandType(false); + nand_type_sys = CheckNandType(NAND_SYSNAND); } else if (pdrv < 7) { - nand_type_emu = CheckNandType(true); + nand_type_emu = CheckNandType(NAND_EMUNAND); + } else if (pdrv < 10) { + nand_type_img = CheckNandType(NAND_IMGNAND); } return RES_OK; } @@ -135,12 +145,14 @@ DRESULT disk_read ( if (sdmmc_sdcard_readsectors(sector, count, buff)) { return RES_PARERR; } + } else if (type == TYPE_IMAGE) { + return RES_PARERR; } else { SubtypeDesc* subtype = get_subtype_desc(pdrv); BYTE keyslot = subtype->keyslot; DWORD isector = subtype->offset + sector; - if (ReadNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND)) + if (ReadNandSectors(buff, isector, count, keyslot, type)) return RES_PARERR; } @@ -168,12 +180,14 @@ DRESULT disk_write ( if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { return RES_PARERR; } + } else if (type == TYPE_IMAGE) { + return RES_PARERR; } else { SubtypeDesc* subtype = get_subtype_desc(pdrv); BYTE keyslot = subtype->keyslot; DWORD isector = subtype->offset + sector; - if (WriteNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND)) + if (WriteNandSectors(buff, isector, count, keyslot, type)) return RES_PARERR; // unstubbed! } @@ -197,13 +211,17 @@ DRESULT disk_ioctl ( void *buff /* Buffer to send/receive control data */ ) { + BYTE type = DriveInfo[pdrv].type; + switch (cmd) { case GET_SECTOR_SIZE: *((DWORD*) buff) = 0x200; return RES_OK; case GET_SECTOR_COUNT: - if (DriveInfo[pdrv].type == TYPE_SDCARD) { + if (type == TYPE_SDCARD) { *((DWORD*) buff) = getMMCDevice(1)->total_size; + } else if (type == TYPE_IMAGE) { + *((DWORD*) buff) = GetMountSize(); } else { *((DWORD*) buff) = get_subtype_desc(pdrv)->size; } @@ -212,7 +230,9 @@ DRESULT disk_ioctl ( *((DWORD*) buff) = 0x2000; return RES_OK; case CTRL_SYNC: - // nothing to do here - the disk_write function handles that + if ((type == TYPE_IMAGE) || (type == TYPE_IMGNAND)) + SyncImage(); + // nothing else to do here - sdmmc.c handles that return RES_OK; } return RES_PARERR; diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c index 41de2fc..482df24 100644 --- a/source/fatfs/ff.c +++ b/source/fatfs/ff.c @@ -456,7 +456,7 @@ WCHAR ff_wtoupper(WCHAR chr) / or start-up routine being used is out of ANSI-C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 9 +#if _VOLUMES < 1 || _VOLUMES > 10 // <--- increased the limit to 10 (this won't break anything, no?) #error Wrong _VOLUMES setting #endif static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h index 2af0522..c267ec3 100644 --- a/source/fatfs/ffconf.h +++ b/source/fatfs/ffconf.h @@ -141,11 +141,11 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define _VOLUMES 7 +#define _VOLUMES 10 /* Number of volumes (logical drives) to be used. */ -#define _STR_VOLUME_ID 1 +#define _STR_VOLUME_ID 0 #define _VOLUME_STRS "sdcard","sysnand","systwln","systwlp","emunand","emutwln","emutwlp" /* _STR_VOLUME_ID option switches string volume ID feature. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive diff --git a/source/fatfs/image.c b/source/fatfs/image.c new file mode 100644 index 0000000..1962936 --- /dev/null +++ b/source/fatfs/image.c @@ -0,0 +1,80 @@ +#include "image.h" +#include "fatfs/ff.h" + +FIL mount_file; +u32 mount_state = IMG_NONE; + +int ReadImageSectors(u8* buffer, u32 sector, u32 count) { + UINT bytes_read; + UINT ret; + if (!mount_state) return FR_INVALID_OBJECT; + if (f_tell(&mount_file) != sector * 0x200) + f_lseek(&mount_file, sector * 0x200); + ret = f_read(&mount_file, buffer, count * 0x200, &bytes_read); + return (ret != 0) ? ret : (bytes_read != count * 0x200) ? -1 : 0; +} + +int WriteImageSectors(const u8* buffer, u32 sector, u32 count) { + UINT bytes_written; + UINT ret; + if (!mount_state) return FR_INVALID_OBJECT; + if (f_tell(&mount_file) != sector * 0x200) + f_lseek(&mount_file, sector * 0x200); + ret = f_write(&mount_file, buffer, count * 0x200, &bytes_written); + return (ret != 0) ? ret : (bytes_written != count * 0x200) ? -1 : 0; +} + +int SyncImage(void) { + return (mount_state) ? f_sync(&mount_file) : FR_INVALID_OBJECT; +} + +u64 GetMountSize(void) { + return mount_state ? f_size(&mount_file) : 0; +} + +u32 GetMountState(void) { + return mount_state; +} + +u32 IdentifyImage(const char* path) { + u8 header[0x200]; + FIL file; + if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) + return IMG_NONE; + f_lseek(&file, 0); + f_sync(&file); + UINT fsize = f_size(&file); + UINT bytes_read; + if ((f_read(&file, header, 0x200, &bytes_read) != FR_OK) || (bytes_read != 0x200)) { + f_close(&file); + return IMG_NONE; + } + f_close(&file); + if ((getbe32(header + 0x100) == 0x4E435344) && (getbe64(header + 0x110) == (u64) 0x0104030301000000) && (getbe64(header + 0x108) == (u64) 0)) { + return IMG_NAND; + } else if (getbe16(header + 0x1FE) == 0x55AA) { // migt be FAT or MBR + if ((strncmp((char*) header + 0x36, "FAT12 ", 8) == 0) || (strncmp((char*) header + 0x36, "FAT16 ", 8) == 0) || + (strncmp((char*) header + 0x36, "FAT ", 8) == 0) || (strncmp((char*) header + 0x52, "FAT32 ", 8) == 0)) { + return IMG_FAT; // this is an actual FAT header + } else if (((getle32(header + 0x1BE + 0x8) + getle32(header + 0x1BE + 0xC)) < (fsize / 0x200)) && // check file size + (getle32(header + 0x1BE + 0x8) > 0) && (getle32(header + 0x1BE + 0xC) >= 0x800) && // check first partition sanity + ((header[0x1BE + 0x4] == 0x1) || (header[0x1BE + 0x4] == 0x4) || (header[0x1BE + 0x4] == 0x6) || // check filesystem type + (header[0x1BE + 0x4] == 0xB) || (header[0x1BE + 0x4] == 0xC) || (header[0x1BE + 0x4] == 0xE))) { + return IMG_FAT; // this might be an MBR -> give it the benefit of doubt + } + } + return IMG_NONE; +} + +u32 MountImage(const char* path) { + if (mount_state) { + f_close(&mount_file); + mount_state = IMG_NONE; + } + if (!path || !IdentifyImage(path)) return IMG_NONE; + if (f_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) + return IMG_NONE; + f_lseek(&mount_file, 0); + f_sync(&mount_file); + return (mount_state = IdentifyImage(path)); +} diff --git a/source/fatfs/image.h b/source/fatfs/image.h new file mode 100644 index 0000000..fd6096e --- /dev/null +++ b/source/fatfs/image.h @@ -0,0 +1,16 @@ +#pragma once + +#include "common.h" + +#define IMG_NONE 0 +#define IMG_FAT 1 +#define IMG_NAND 2 + +int ReadImageSectors(u8* buffer, u32 sector, u32 count); +int WriteImageSectors(const u8* buffer, u32 sector, u32 count); +int SyncImage(void); + +u64 GetMountSize(void); +u32 GetMountState(void); +u32 IdentifyImage(const char* path); +u32 MountImage(const char* path); diff --git a/source/fs.c b/source/fs.c index 8a9bca3..f26e7fe 100644 --- a/source/fs.c +++ b/source/fs.c @@ -6,7 +6,8 @@ #define MAIN_BUFFER ((u8*)0x21200000) #define MAIN_BUFFER_SIZE (0x100000) // must be multiple of 0x200 -#define MAX_FS 7 +#define NORM_FS 10 +#define VIRT_FS 3 // don't use this area for anything else! static FATFS* fs = (FATFS*)0x20316000; @@ -15,7 +16,7 @@ static FATFS* fs = (FATFS*)0x20316000; static u32 write_permission_level = 1; // number of currently open file systems -static bool fs_mounted[MAX_FS] = { false }; +static bool fs_mounted[NORM_FS] = { false }; bool InitSDCardFS() { #ifndef EXEC_GATEWAY @@ -30,7 +31,7 @@ bool InitSDCardFS() { bool InitNandFS() { if (!fs_mounted[0]) return false; - for (u32 i = 1; i < MAX_FS; i++) { + for (u32 i = 1; i < NORM_FS; i++) { char fsname[8]; snprintf(fsname, 7, "%lu:", i); if (f_mount(fs + i, fsname, 1) != FR_OK) return false; @@ -40,7 +41,7 @@ bool InitNandFS() { } void DeinitNandFS() { - for (u32 i = MAX_FS; i > 0; i--) { + for (u32 i = NORM_FS; i > 0; i--) { if (fs_mounted[i]) { char fsname[8]; snprintf(fsname, 7, "%lu:", i); @@ -59,7 +60,7 @@ void DeinitSDCardFS() { int PathToNumFS(const char* path) { int fsnum = *path - (int) '0'; - if ((fsnum < 0) || (fsnum >= MAX_FS) || (path[1] != ':')) { + if ((fsnum < 0) || (fsnum >= NORM_FS) || (path[1] != ':')) { if (!IsVirtualPath(path)) ShowPrompt(false, "Invalid path (%s)", path); return -1; } @@ -82,6 +83,10 @@ bool CheckWritePermissions(const char* path) { if (ShowPrompt(true, "Writing to the EmuNAND is locked!\nUnlock it now?")) return SetWritePermissions(2); return false; + } else if ((pdrv >= 7) && (pdrv <= 9) && (write_permission_level < 2)) { + if (ShowPrompt(true, "Writing to the images is locked!\nUnlock it now?")) + return SetWritePermissions(2); + return false; } else if ((pdrv == 0) && (write_permission_level < 1)) { if (ShowPrompt(true, "Writing to the SD card is locked!\nUnlock it now?")) return SetWritePermissions(1); @@ -570,18 +575,19 @@ bool GetRootDirContentsWorker(DirStruct* contents) { "SDCARD", "SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP", "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", - "SYSNAND VIRTUAL", "EMUNAND VIRTUAL" + "IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", + "SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL", }; static const char* drvnum[] = { - "0:", "1:", "2:", "3:", "4:", "5:", "6:", "S:", "E:" + "0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "S:", "E:", "I:" }; u32 n_entries = 0; // virtual root objects hacked in - for (u32 pdrv = 0; (pdrv < MAX_FS+2) && (n_entries < MAX_ENTRIES); pdrv++) { + for (u32 pdrv = 0; (pdrv < NORM_FS+VIRT_FS) && (n_entries < MAX_ENTRIES); pdrv++) { DirEntry* entry = &(contents->entry[n_entries]); - if ((pdrv < MAX_FS) && !fs_mounted[pdrv]) continue; - else if ((pdrv >= MAX_FS) && (!CheckVirtualPath(drvnum[pdrv]))) continue; + if ((pdrv < NORM_FS) && !fs_mounted[pdrv]) continue; + else if ((pdrv >= NORM_FS) && (!CheckVirtualPath(drvnum[pdrv]))) continue; memset(entry->path, 0x00, 64); snprintf(entry->path + 0, 4, drvnum[pdrv]); snprintf(entry->path + 4, 32, "[%s] %s", drvnum[pdrv], drvname[pdrv]); diff --git a/source/godmode.c b/source/godmode.c index 8702543..269d287 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -5,8 +5,9 @@ #include "platform.h" #include "nand.h" #include "virtual.h" +#include "image.h" -#define VERSION "0.2.1" +#define VERSION "0.2.3" #define COLOR_TOP_BAR ((GetWritePermissions() == 0) ? COLOR_WHITE : (GetWritePermissions() == 1) ? COLOR_BRIGHTGREEN : (GetWritePermissions() == 2) ? COLOR_BRIGHTYELLOW : COLOR_RED) #define COLOR_SIDE_BAR COLOR_DARKGREY @@ -184,6 +185,20 @@ u32 GodMode() { cursor = 1; scroll = 0; } else cursor = 0; + } else if ((pad_state & BUTTON_A) && (current_dir->entry[cursor].type == T_FILE) && + (PathToNumFS(current_dir->entry[cursor].path) == 0)) { // try to mount image + u32 file_type = IdentifyImage(current_dir->entry[cursor].path); + if (file_type && ShowPrompt(true, "This looks like a %s image\nTry to mount it?", (file_type == IMG_NAND) ? "NAND" : "FAT")) { + if (!MountImage(current_dir->entry[cursor].path)) { + ShowPrompt(false, "Mounting image: failed"); + } else { + DeinitNandFS(); + InitNandFS(); + *current_path = '\0'; + GetDirContents(current_dir, current_path); + cursor = 0; + } + } } else if ((pad_state & BUTTON_B) && *current_path) { // one level down char old_path[256]; char* last_slash = strrchr(current_path, '/'); diff --git a/source/nand/nand.c b/source/nand/nand.c index b7ac339..38a3026 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -4,9 +4,11 @@ #include "sha.h" #include "sdmmc.h" #include "nand.h" +#include "image.h" #define NAND_BUFFER ((u8*)0x21100000) #define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200 +#define NAND_MIN_SIZE ((GetUnitPlatform() == PLATFORM_N3DS) ? 0x26C000 : 0x1D7800) static u8 slot0x05KeyY[0x10] = { 0x00 }; // need to load this from file static u8 slot0x05KeyY_sha256[0x20] = { // hash for slot0x05KeyY file @@ -102,11 +104,9 @@ bool CheckSlot0x05Crypto(void) const u8 magic[8] = {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}; const u32 sector = 0x05CAD7; u8 buffer[0x200]; - for (u32 nand = 0; nand < 2; nand++) { - ReadNandSectors(buffer, sector, 1, 0x05, nand); - if (memcmp(buffer, magic, 8) == 0) - return true; - } + ReadNandSectors(buffer, sector, 1, 0x05, NAND_SYSNAND); + if (memcmp(buffer, magic, 8) == 0) + return true; // failed if we arrive here return false; @@ -132,9 +132,9 @@ void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot) } } -int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand) +int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_src) { - if (read_emunand) { + if (nand_src == NAND_EMUNAND) { // EmuNAND int errorcode = 0; if ((sector == 0) && (emunand_base_sector % 0x200000 == 0)) { // GW EmuNAND header handling errorcode = sdmmc_sdcard_readsectors(emunand_base_sector + getMMCDevice(0)->total_size, 1, buffer); @@ -144,70 +144,83 @@ int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_em } errorcode = (!errorcode && count) ? sdmmc_sdcard_readsectors(emunand_base_sector + sector, count, buffer) : errorcode; if (errorcode) return errorcode; - } else { + } else if (nand_src == NAND_IMGNAND) { // ImgNAND + int errorcode = ReadImageSectors(buffer, sector, count); + if (errorcode) return errorcode; + } else if (nand_src == NAND_SYSNAND) { // SysNAND int errorcode = sdmmc_nand_readsectors(sector, count, buffer); if (errorcode) return errorcode; + } else { + return -1; } if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot); return 0; } -int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool write_emunand) +int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_dst) { // buffer must not be changed, so this is a little complicated for (u32 s = 0; s < count; s += (NAND_BUFFER_SIZE / 0x200)) { u32 pcount = min((NAND_BUFFER_SIZE/0x200), (count - s)); memcpy(NAND_BUFFER, buffer + (s*0x200), pcount * 0x200); if (keyslot < 0x40) CryptNand(NAND_BUFFER, sector + s, pcount, keyslot); - if (write_emunand) { + if (nand_dst == NAND_EMUNAND) { int errorcode = 0; if ((sector + s == 0) && (emunand_base_sector % 0x200000 == 0)) { // GW EmuNAND header handling errorcode = sdmmc_sdcard_writesectors(emunand_base_sector + getMMCDevice(0)->total_size, 1, NAND_BUFFER); errorcode = (!errorcode && (pcount > 1)) ? sdmmc_sdcard_writesectors(emunand_base_sector + 1, pcount - 1, NAND_BUFFER + 0x200) : errorcode; } else errorcode = sdmmc_sdcard_writesectors(emunand_base_sector + sector + s, pcount, NAND_BUFFER); if (errorcode) return errorcode; - } else { + } else if (nand_dst == NAND_IMGNAND) { + int errorcode = WriteImageSectors(NAND_BUFFER, sector + s, pcount); + if (errorcode) return errorcode; + } else if (nand_dst == NAND_SYSNAND) { int errorcode = sdmmc_nand_writesectors(sector + s, pcount, NAND_BUFFER); - if (errorcode) return errorcode; + if (errorcode) return errorcode; + } else { + return -1; } } return 0; } -u8 CheckNandType(bool check_emunand) +u8 CheckNandType(u32 nand_src) { - if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, check_emunand) != 0) - return NAND_TYPE_UNK; + if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, nand_src) != 0) + return NAND_UNKNOWN; if (memcmp(NAND_BUFFER + 0x100, nand_magic_n3ds, 0x60) == 0) { return NAND_TYPE_N3DS; } else if (memcmp(NAND_BUFFER + 0x100, nand_magic_o3ds, 0x60) == 0) { return (GetUnitPlatform() == PLATFORM_3DS) ? NAND_TYPE_O3DS : NAND_TYPE_NO3DS; } - return NAND_TYPE_UNK; + return NAND_UNKNOWN; } -u64 GetNandSizeSectors(bool size_emunand) +u64 GetNandSizeSectors(u32 nand_src) { - if (size_emunand) { // for EmuNAND + u32 sysnand_sectors = getMMCDevice(0)->total_size; + if (nand_src == NAND_EMUNAND) { // for EmuNAND u32 emunand_max_sectors = GetPartitionOffsetSector("0:") - (emunand_base_sector + 1); // +1 for safety - u32 emunand_min_sectors = (emunand_base_sector % 0x200000 == 0) ? getMMCDevice(0)->total_size : - (GetUnitPlatform() == PLATFORM_N3DS) ? 0x26C000 : 0x1D7800; - if (emunand_max_sectors >= getMMCDevice(0)->total_size) return getMMCDevice(0)->total_size; + u32 emunand_min_sectors = (emunand_base_sector % 0x200000 == 0) ? sysnand_sectors : NAND_MIN_SIZE; + if (emunand_max_sectors >= sysnand_sectors) return sysnand_sectors; else return (emunand_min_sectors > emunand_max_sectors) ? 0 : emunand_min_sectors; - } else return getMMCDevice(0)->total_size; // for SysNAND + } else if (nand_src == NAND_IMGNAND) { + u32 img_size = (GetMountState() == IMG_NAND) ? GetMountSize() : 0; + return (img_size > sysnand_sectors) ? sysnand_sectors : (img_size > NAND_MIN_SIZE) ? NAND_MIN_SIZE : 0; + } else return sysnand_sectors; // for SysNAND } bool InitEmuNandBase(void) { emunand_base_sector = 0x000000; // GW type EmuNAND - if (CheckNandType(true) != NAND_TYPE_UNK) + if (CheckNandType(NAND_EMUNAND) != NAND_UNKNOWN) return true; emunand_base_sector = 0x000001; // RedNAND type EmuNAND - if (CheckNandType(true) != NAND_TYPE_UNK) + if (CheckNandType(NAND_EMUNAND) != NAND_UNKNOWN) return true; if (GetPartitionOffsetSector("0:") > getMMCDevice(0)->total_size) diff --git a/source/nand/nand.h b/source/nand/nand.h index f2b5405..faa326d 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -2,19 +2,22 @@ #include "common.h" -#define NAND_TYPE_UNK 0 -#define NAND_TYPE_O3DS (1<<0) -#define NAND_TYPE_N3DS (1<<1) -#define NAND_TYPE_NO3DS (1<<2) +#define NAND_UNKNOWN 0 +#define NAND_SYSNAND (1<<0) +#define NAND_EMUNAND (1<<1) +#define NAND_IMGNAND (1<<2) +#define NAND_TYPE_O3DS (1<<3) +#define NAND_TYPE_N3DS (1<<4) +#define NAND_TYPE_NO3DS (1<<5) bool InitNandCrypto(void); bool CheckSlot0x05Crypto(void); void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot); -int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand); -int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool write_emunand); +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(bool size_emunand); -u8 CheckNandType(bool check_emunand); +u64 GetNandSizeSectors(u32 src); +u8 CheckNandType(u32 src); bool InitEmuNandBase(void); diff --git a/source/nand/virtual.c b/source/nand/virtual.c index eb003c6..db89e6d 100644 --- a/source/nand/virtual.c +++ b/source/nand/virtual.c @@ -4,8 +4,7 @@ #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_NAND_SIZE (1<<30) -#define VFLAG_ON_EMUNAND (1<<31) +#define VFLAG_NAND_SIZE (1<<31) VirtualFile virtualFileTemplates[] = { { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL }, @@ -32,23 +31,23 @@ u32 IsVirtualPath(const char* path) { 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; return 0; } bool CheckVirtualPath(const char* path) { u32 vp_nand = IsVirtualPath(path); - if (vp_nand == VRT_SYSNAND) { - return true; // this is safe because we re-check for slot0x05 crypto - } else if (vp_nand == VRT_EMUNAND) { - return GetNandSizeSectors(true); + if ((vp_nand == VRT_EMUNAND) || (vp_nand == VRT_IMGNAND)) { + return GetNandSizeSectors(vp_nand); } - return false; + return vp_nand; // this is safe for SysNAND because we re-check for slot0x05 crypto } bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) { char* fname = strchr(path, '/'); - bool on_emunand = false; + u8 nand_src = 0; u8 nand_type = 0; // fix the name @@ -56,12 +55,12 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) fname++; // check path vailidity - if (!IsVirtualPath(path) || (fname - path != 3)) + nand_src = IsVirtualPath(path); + if (!nand_src || (fname - path != 3)) return false; // check NAND type - on_emunand = (IsVirtualPath(path) == VRT_EMUNAND); - nand_type = CheckNandType(on_emunand); + nand_type = CheckNandType(nand_src); // parse the template list, get the correct one u32 n_templates = sizeof(virtualFileTemplates) / sizeof(VirtualFile); @@ -83,23 +82,25 @@ 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 (on_emunand && (GetNandSizeSectors(false) != GetNandSizeSectors(true))) - return false; // EmuNAND is too small - vfile->size = GetNandSizeSectors(false) * 0x200; + if ((nand_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src))) + return false; // EmuNAND/IMGNAND is too small + vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200; } - if (on_emunand) vfile->flags |= VFLAG_ON_EMUNAND; + vfile->flags |= nand_src; return true; } int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { - // simple wrapper function for ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand) - return ReadNandSectors(buffer, (vfile->offset + offset) / 0x200, (count+0x1FF) / 0x200, vfile->keyslot, vfile->flags & VFLAG_ON_EMUNAND); + // simple wrapper function for ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src) + return ReadNandSectors(buffer, (vfile->offset + offset) / 0x200, (count+0x1FF) / 0x200, vfile->keyslot, + vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); } int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count) { - // simple wrapper function for WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool write_emunand) - return WriteNandSectors(buffer, (vfile->offset + offset) / 0x200, (count+0x1FF) / 0x200, vfile->keyslot, vfile->flags & VFLAG_ON_EMUNAND); + // simple wrapper function for WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest) + return WriteNandSectors(buffer, (vfile->offset + offset) / 0x200, (count+0x1FF) / 0x200, vfile->keyslot, + vfile->flags & (VRT_SYSNAND | VRT_EMUNAND | VRT_IMGNAND)); } diff --git a/source/nand/virtual.h b/source/nand/virtual.h index 1afa5cc..dcb2041 100644 --- a/source/nand/virtual.h +++ b/source/nand/virtual.h @@ -4,8 +4,9 @@ #include "nand.h" #define VRT_NONE 0 -#define VRT_SYSNAND 1 -#define VRT_EMUNAND 2 +#define VRT_SYSNAND NAND_SYSNAND +#define VRT_EMUNAND NAND_EMUNAND +#define VRT_IMGNAND NAND_IMGNAND 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",