From 38fccfb28b3a36bc98733fe8ad5928fa7a2b4e79 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Tue, 15 Mar 2016 16:25:27 +0100 Subject: [PATCH] Enable handling of downgraded (2.x) N3DS NANDs --- source/fatfs/diskio.c | 61 +++++++++++++++++++++++++++++++------------ source/nand/nand.c | 50 ++++++++++++++++++++++++++++++++--- source/nand/nand.h | 7 +++++ 3 files changed, 98 insertions(+), 20 deletions(-) diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index da5cf1b..c369899 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -8,7 +8,6 @@ /*-----------------------------------------------------------------------*/ #include "diskio.h" /* FatFs lower layer API */ -#include "platform.h" #include "nand.h" #include "sdmmc.h" @@ -18,11 +17,10 @@ #define SUBTYPE_CTRN 0 #define SUBTYPE_CTRN_N 1 -#define SUBTYPE_TWLN 2 -#define SUBTYPE_TWLP 3 -#define SUBTYPE_NONE 4 - -#define SUBTYPE(pd) ((mode_n3ds && (DriveInfo[pd].subtype == SUBTYPE_CTRN)) ? SUBTYPE_CTRN_N : DriveInfo[pd].subtype) +#define SUBTYPE_CTRN_NO 2 +#define SUBTYPE_TWLN 3 +#define SUBTYPE_TWLP 4 +#define SUBTYPE_NONE 5 typedef struct { BYTE type; @@ -45,14 +43,42 @@ FATpartition DriveInfo[7] = { { TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND TWLP }; -SubtypeDesc SubTypes[4] = { +SubtypeDesc SubTypes[5] = { { 0x05CAE5, 0x179F1B, 0x4 }, // O3DS CTRNAND { 0x05CAD7, 0x20E969, 0x5 }, // N3DS CTRNAND + { 0x05CAD7, 0x20E969, 0x4 }, // N3DS CTRNAND (downgraded) { 0x000097, 0x047DA9, 0x3 }, // TWLN { 0x04808D, 0x0105B3, 0x3 } // TWLP }; -static bool mode_n3ds = false; +static BYTE nand_type_sys = NAND_TYPE_UNK; +static BYTE nand_type_emu = NAND_TYPE_UNK; + + + +/*-----------------------------------------------------------------------*/ +/* Get Drive Subtype helper */ +/*-----------------------------------------------------------------------*/ + +SubtypeDesc* get_subtype_desc( + __attribute__((unused)) + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + BYTE type = DriveInfo[pdrv].type; + BYTE subtype = DriveInfo[pdrv].subtype; + + if (type == TYPE_SDCARD) { + return NULL; + } else if (subtype == SUBTYPE_CTRN) { + BYTE nand_type = (type == TYPE_SYSNAND) ? nand_type_sys : nand_type_emu; + if (nand_type != NAND_TYPE_O3DS) + subtype = (nand_type == NAND_TYPE_N3DS) ? SUBTYPE_CTRN_N : SUBTYPE_CTRN_NO; + } + + return &(SubTypes[subtype]); +} + /*-----------------------------------------------------------------------*/ @@ -79,8 +105,11 @@ DSTATUS disk_initialize ( ) { if (pdrv == 0) { // a mounted SD card is the preriquisite for everything else - mode_n3ds = (GetUnitPlatform() == PLATFORM_N3DS); sdmmc_sdcard_init(); + } else if (pdrv < 4) { + nand_type_sys = CheckNandType(false); + } else if (pdrv < 7) { + nand_type_emu = CheckNandType(true); } return RES_OK; } @@ -106,9 +135,9 @@ DRESULT disk_read ( return RES_PARERR; } } else { - BYTE subtype = SUBTYPE(pdrv); - BYTE keyslot = SubTypes[subtype].keyslot; - DWORD isector = SubTypes[subtype].offset + sector; + SubtypeDesc* subtype = get_subtype_desc(pdrv); + BYTE keyslot = subtype->keyslot; + DWORD isector = subtype->offset + sector; if (ReadNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND)) return RES_PARERR; @@ -139,9 +168,9 @@ DRESULT disk_write ( return RES_PARERR; } } else { - BYTE subtype = SUBTYPE(pdrv); - BYTE keyslot = SubTypes[subtype].keyslot; - DWORD isector = SubTypes[subtype].offset + sector; + SubtypeDesc* subtype = get_subtype_desc(pdrv); + BYTE keyslot = subtype->keyslot; + DWORD isector = subtype->offset + sector; if (WriteNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND)) return RES_PARERR; // unstubbed! @@ -175,7 +204,7 @@ DRESULT disk_ioctl ( if (DriveInfo[pdrv].type == TYPE_SDCARD) { *((DWORD*) buff) = getMMCDevice(1)->total_size; } else { - *((DWORD*) buff) = SubTypes[SUBTYPE(pdrv)].size; + *((DWORD*) buff) = get_subtype_desc(pdrv)->size; } return RES_OK; case GET_BLOCK_SIZE: diff --git a/source/nand/nand.c b/source/nand/nand.c index e359187..86ea2eb 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -10,6 +10,24 @@ #define NAND_BUFFER ((u8*)0x21100000) #define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200 +static u8 nand_magic_n3ds[0x60] = { // NCSD NAND header N3DS magic + 0x4E, 0x43, 0x53, 0x44, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x05, 0x00, 0x00, 0x88, 0x05, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x89, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0xA9, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x80, 0xC9, 0x05, 0x00, 0x80, 0xF6, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static u8 nand_magic_o3ds[0x60] = { // NCSD NAND header O3DS magic + 0x4E, 0x43, 0x53, 0x44, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x05, 0x00, 0x00, 0x88, 0x05, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x89, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0xA9, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x80, 0xC9, 0x05, 0x00, 0x80, 0xAE, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static u8 CtrNandCtr[16]; static u8 TwlNandCtr[16]; @@ -93,13 +111,20 @@ void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot) int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand) { if (read_emunand) { - int errorcode = sdmmc_sdcard_readsectors(emunand_base_sector + sector, count, buffer); + 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); + sector = 1; + count--; + buffer += 0x200; + } + errorcode = (!errorcode && count) ? sdmmc_sdcard_readsectors(emunand_base_sector + sector, count, buffer) : errorcode; if (errorcode) return errorcode; } else { int errorcode = sdmmc_nand_readsectors(sector, count, buffer); if (errorcode) return errorcode; } - CryptNand(buffer, sector, count, keyslot); + if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot); return 0; } @@ -110,9 +135,13 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool 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); - CryptNand(NAND_BUFFER, sector + s, pcount, keyslot); + if (keyslot < 0x40) CryptNand(NAND_BUFFER, sector + s, pcount, keyslot); if (write_emunand) { - int errorcode = sdmmc_sdcard_writesectors(emunand_base_sector + sector + s, pcount, NAND_BUFFER); + 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 { int errorcode = sdmmc_nand_writesectors(sector + s, pcount, NAND_BUFFER); @@ -123,6 +152,19 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool return 0; } +u8 CheckNandType(bool check_emunand) +{ + if (ReadNandSectors(NAND_BUFFER, 0, 1, 0xFF, check_emunand) != 0) + return NAND_TYPE_UNK; + 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; +} + u32 GetEmuNandBase(void) { return emunand_base_sector; diff --git a/source/nand/nand.h b/source/nand/nand.h index b315792..42179df 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -2,12 +2,19 @@ #include "common.h" +#define NAND_TYPE_UNK 0 +#define NAND_TYPE_O3DS 1 +#define NAND_TYPE_N3DS 2 +#define NAND_TYPE_NO3DS 3 + bool InitNandCrypto(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); +u8 CheckNandType(bool check_emunand); + u32 GetEmuNandBase(void); u32 SwitchEmuNandBase(int start_sector);