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 "diskio.h" /* FatFs lower layer API */
|
||||||
#include "platform.h"
|
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
|
|
||||||
@ -18,11 +17,10 @@
|
|||||||
|
|
||||||
#define SUBTYPE_CTRN 0
|
#define SUBTYPE_CTRN 0
|
||||||
#define SUBTYPE_CTRN_N 1
|
#define SUBTYPE_CTRN_N 1
|
||||||
#define SUBTYPE_TWLN 2
|
#define SUBTYPE_CTRN_NO 2
|
||||||
#define SUBTYPE_TWLP 3
|
#define SUBTYPE_TWLN 3
|
||||||
#define SUBTYPE_NONE 4
|
#define SUBTYPE_TWLP 4
|
||||||
|
#define SUBTYPE_NONE 5
|
||||||
#define SUBTYPE(pd) ((mode_n3ds && (DriveInfo[pd].subtype == SUBTYPE_CTRN)) ? SUBTYPE_CTRN_N : DriveInfo[pd].subtype)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BYTE type;
|
BYTE type;
|
||||||
@ -45,14 +43,42 @@ FATpartition DriveInfo[7] = {
|
|||||||
{ TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND TWLP
|
{ TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND TWLP
|
||||||
};
|
};
|
||||||
|
|
||||||
SubtypeDesc SubTypes[4] = {
|
SubtypeDesc SubTypes[5] = {
|
||||||
{ 0x05CAE5, 0x179F1B, 0x4 }, // O3DS CTRNAND
|
{ 0x05CAE5, 0x179F1B, 0x4 }, // O3DS CTRNAND
|
||||||
{ 0x05CAD7, 0x20E969, 0x5 }, // N3DS CTRNAND
|
{ 0x05CAD7, 0x20E969, 0x5 }, // N3DS CTRNAND
|
||||||
|
{ 0x05CAD7, 0x20E969, 0x4 }, // N3DS CTRNAND (downgraded)
|
||||||
{ 0x000097, 0x047DA9, 0x3 }, // TWLN
|
{ 0x000097, 0x047DA9, 0x3 }, // TWLN
|
||||||
{ 0x04808D, 0x0105B3, 0x3 } // TWLP
|
{ 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
|
if (pdrv == 0) { // a mounted SD card is the preriquisite for everything else
|
||||||
mode_n3ds = (GetUnitPlatform() == PLATFORM_N3DS);
|
|
||||||
sdmmc_sdcard_init();
|
sdmmc_sdcard_init();
|
||||||
|
} else if (pdrv < 4) {
|
||||||
|
nand_type_sys = CheckNandType(false);
|
||||||
|
} else if (pdrv < 7) {
|
||||||
|
nand_type_emu = CheckNandType(true);
|
||||||
}
|
}
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
@ -106,9 +135,9 @@ DRESULT disk_read (
|
|||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BYTE subtype = SUBTYPE(pdrv);
|
SubtypeDesc* subtype = get_subtype_desc(pdrv);
|
||||||
BYTE keyslot = SubTypes[subtype].keyslot;
|
BYTE keyslot = subtype->keyslot;
|
||||||
DWORD isector = SubTypes[subtype].offset + sector;
|
DWORD isector = subtype->offset + sector;
|
||||||
|
|
||||||
if (ReadNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND))
|
if (ReadNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND))
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
@ -139,9 +168,9 @@ DRESULT disk_write (
|
|||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BYTE subtype = SUBTYPE(pdrv);
|
SubtypeDesc* subtype = get_subtype_desc(pdrv);
|
||||||
BYTE keyslot = SubTypes[subtype].keyslot;
|
BYTE keyslot = subtype->keyslot;
|
||||||
DWORD isector = SubTypes[subtype].offset + sector;
|
DWORD isector = subtype->offset + sector;
|
||||||
|
|
||||||
if (WriteNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND))
|
if (WriteNandSectors(buff, isector, count, keyslot, type == TYPE_EMUNAND))
|
||||||
return RES_PARERR; // unstubbed!
|
return RES_PARERR; // unstubbed!
|
||||||
@ -175,7 +204,7 @@ DRESULT disk_ioctl (
|
|||||||
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
||||||
*((DWORD*) buff) = getMMCDevice(1)->total_size;
|
*((DWORD*) buff) = getMMCDevice(1)->total_size;
|
||||||
} else {
|
} else {
|
||||||
*((DWORD*) buff) = SubTypes[SUBTYPE(pdrv)].size;
|
*((DWORD*) buff) = get_subtype_desc(pdrv)->size;
|
||||||
}
|
}
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
case GET_BLOCK_SIZE:
|
case GET_BLOCK_SIZE:
|
||||||
|
@ -10,6 +10,24 @@
|
|||||||
#define NAND_BUFFER ((u8*)0x21100000)
|
#define NAND_BUFFER ((u8*)0x21100000)
|
||||||
#define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200
|
#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 CtrNandCtr[16];
|
||||||
static u8 TwlNandCtr[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)
|
int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand)
|
||||||
{
|
{
|
||||||
if (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;
|
if (errorcode) return errorcode;
|
||||||
} else {
|
} else {
|
||||||
int errorcode = sdmmc_nand_readsectors(sector, count, buffer);
|
int errorcode = sdmmc_nand_readsectors(sector, count, buffer);
|
||||||
if (errorcode) return errorcode;
|
if (errorcode) return errorcode;
|
||||||
}
|
}
|
||||||
CryptNand(buffer, sector, count, keyslot);
|
if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot);
|
||||||
|
|
||||||
return 0;
|
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)) {
|
for (u32 s = 0; s < count; s += (NAND_BUFFER_SIZE / 0x200)) {
|
||||||
u32 pcount = min((NAND_BUFFER_SIZE/0x200), (count - s));
|
u32 pcount = min((NAND_BUFFER_SIZE/0x200), (count - s));
|
||||||
memcpy(NAND_BUFFER, buffer + (s*0x200), pcount * 0x200);
|
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) {
|
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;
|
if (errorcode) return errorcode;
|
||||||
} else {
|
} else {
|
||||||
int errorcode = sdmmc_nand_writesectors(sector + s, pcount, NAND_BUFFER);
|
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;
|
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)
|
u32 GetEmuNandBase(void)
|
||||||
{
|
{
|
||||||
return emunand_base_sector;
|
return emunand_base_sector;
|
||||||
|
@ -2,12 +2,19 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#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);
|
bool InitNandCrypto(void);
|
||||||
void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot);
|
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, bool read_emunand);
|
||||||
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, bool write_emunand);
|
||||||
|
|
||||||
|
u8 CheckNandType(bool check_emunand);
|
||||||
|
|
||||||
u32 GetEmuNandBase(void);
|
u32 GetEmuNandBase(void);
|
||||||
u32 SwitchEmuNandBase(int start_sector);
|
u32 SwitchEmuNandBase(int start_sector);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user