mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Enable handling of downgraded (2.x) N3DS NANDs
This commit is contained in:
parent
1debcaeecc
commit
38fccfb28b
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user