Support for mounting NAND images

This commit is contained in:
d0k3 2016-04-04 22:45:49 +02:00
parent 59126078c7
commit 00fe5b9b36
11 changed files with 236 additions and 81 deletions

View File

@ -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;

View File

@ -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) */

View File

@ -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

80
source/fatfs/image.c Normal file
View File

@ -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));
}

16
source/fatfs/image.h Normal file
View File

@ -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);

View File

@ -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]);

View File

@ -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, '/');

View File

@ -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)

View File

@ -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);

View File

@ -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));
}

View File

@ -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",