forked from Mirror/GodMode9
Improved, minimized, cleaned up NAND FAT access
This commit is contained in:
parent
ec5213255d
commit
905267e0e5
@ -8,54 +8,133 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "aes.h"
|
||||
#include "platform.h"
|
||||
#include "sdmmc.h"
|
||||
#include "nandio.h"
|
||||
|
||||
#define TYPE_SDCARD 0
|
||||
#define TYPE_SYSNAND 1
|
||||
#define TYPE_EMUNAND 2
|
||||
|
||||
#define SUBTYPE_CTRN_O 0
|
||||
#define SUBTYPE_CTRN_N 1
|
||||
#define SUBTYPE_TWLN 2
|
||||
#define SUBTYPE_TWLP 3
|
||||
#define SUBTYPE_NONE 4
|
||||
|
||||
typedef struct {
|
||||
DWORD offset;
|
||||
BYTE type;
|
||||
DWORD subtype;
|
||||
BYTE subtype;
|
||||
} FATpartition;
|
||||
|
||||
FATpartition DriveInfo[28] = {
|
||||
{ 0x000000, TYPE_SDCARD, 0 }, // 0 - SDCARD
|
||||
{ 0x000000, TYPE_SYSNAND, P_CTRNAND }, // 1 - SYSNAND CTRNAND
|
||||
{ 0x000000, TYPE_SYSNAND, P_TWLN }, // 2 - SYSNAND TWLN
|
||||
{ 0x000000, TYPE_SYSNAND, P_TWLP }, // 3 - SYSNAND TWLP
|
||||
{ 0x000000, TYPE_EMUNAND, P_CTRNAND }, // 4 - EMUNAND0 O3DS CTRNAND
|
||||
{ 0x000000, TYPE_EMUNAND, P_TWLN }, // 5 - EMUNAND0 O3DS TWLN
|
||||
{ 0x000000, TYPE_EMUNAND, P_TWLP }, // 6 - EMUNAND0 O3DS TWLP
|
||||
{ 0x200000, TYPE_EMUNAND, P_CTRNAND }, // 7 - EMUNAND1 O3DS CTRNAND
|
||||
{ 0x200000, TYPE_EMUNAND, P_TWLN }, // 8 - EMUNAND1 O3DS TWLN
|
||||
{ 0x200000, TYPE_EMUNAND, P_TWLP }, // 9 - EMUNAND1 O3DS TWLP
|
||||
{ 0x400000, TYPE_EMUNAND, P_CTRNAND }, // 10 - EMUNAND2 O3DS CTRNAND
|
||||
{ 0x400000, TYPE_EMUNAND, P_TWLN }, // 11 - EMUNAND2 O3DS TWLN
|
||||
{ 0x400000, TYPE_EMUNAND, P_TWLP }, // 12 - EMUNAND2 O3DS TWLP
|
||||
{ 0x600000, TYPE_EMUNAND, P_CTRNAND }, // 13 - EMUNAND3 O3DS CTRNAND
|
||||
{ 0x600000, TYPE_EMUNAND, P_TWLN }, // 14 - EMUNAND3 O3DS TWLN
|
||||
{ 0x600000, TYPE_EMUNAND, P_TWLP }, // 15 - EMUNAND3 O3DS TWLP
|
||||
{ 0x000000, TYPE_EMUNAND, P_CTRNAND }, // 16 - EMUNAND0 N3DS CTRNAND
|
||||
{ 0x000000, TYPE_EMUNAND, P_TWLN }, // 17 - EMUNAND0 N3DS TWLN
|
||||
{ 0x000000, TYPE_EMUNAND, P_TWLP }, // 18 - EMUNAND0 N3DS TWLP
|
||||
{ 0x400000, TYPE_EMUNAND, P_CTRNAND }, // 19 - EMUNAND1 N3DS CTRNAND
|
||||
{ 0x400000, TYPE_EMUNAND, P_TWLN }, // 20 - EMUNAND1 N3DS TWLN
|
||||
{ 0x400000, TYPE_EMUNAND, P_TWLP }, // 21 - EMUNAND1 N3DS TWLP
|
||||
{ 0x800000, TYPE_EMUNAND, P_CTRNAND }, // 22 - EMUNAND2 N3DS CTRNAND
|
||||
{ 0x800000, TYPE_EMUNAND, P_TWLN }, // 23 - EMUNAND2 N3DS TWLN
|
||||
{ 0x800000, TYPE_EMUNAND, P_TWLP }, // 24 - EMUNAND2 N3DS TWLP
|
||||
{ 0xC00000, TYPE_EMUNAND, P_CTRNAND }, // 25 - EMUNAND3 N3DS CTRNAND
|
||||
{ 0xC00000, TYPE_EMUNAND, P_TWLN }, // 26 - EMUNAND3 N3DS TWLN
|
||||
{ 0xC00000, TYPE_EMUNAND, P_TWLP } // 27 - EMUNAND3 N3DS TWLP
|
||||
typedef struct {
|
||||
DWORD offset;
|
||||
DWORD mode;
|
||||
BYTE keyslot;
|
||||
} SubtypeDesc;
|
||||
|
||||
FATpartition DriveInfo[31] = {
|
||||
{ 0x000000, TYPE_SDCARD, SUBTYPE_NONE }, // 0 - SDCARD
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_CTRN_O }, // 1 - SYSNAND CTRNAND
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_TWLN }, // 2 - SYSNAND TWLN
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_TWLP }, // 3 - SYSNAND TWLP
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_CTRN_O }, // 4 - EMUNAND0 O3DS CTRNAND
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_TWLN }, // 5 - EMUNAND0 O3DS TWLN
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND0 O3DS TWLP
|
||||
{ 0x200000, TYPE_EMUNAND, SUBTYPE_CTRN_O }, // 7 - EMUNAND1 O3DS CTRNAND
|
||||
{ 0x200000, TYPE_EMUNAND, SUBTYPE_TWLN }, // 8 - EMUNAND1 O3DS TWLN
|
||||
{ 0x200000, TYPE_EMUNAND, SUBTYPE_TWLP }, // 9 - EMUNAND1 O3DS TWLP
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_CTRN_O }, // 10 - EMUNAND2 O3DS CTRNAND
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_TWLN }, // 11 - EMUNAND2 O3DS TWLN
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_TWLP }, // 12 - EMUNAND2 O3DS TWLP
|
||||
{ 0x600000, TYPE_EMUNAND, SUBTYPE_CTRN_O }, // 13 - EMUNAND3 O3DS CTRNAND
|
||||
{ 0x600000, TYPE_EMUNAND, SUBTYPE_TWLN }, // 14 - EMUNAND3 O3DS TWLN
|
||||
{ 0x600000, TYPE_EMUNAND, SUBTYPE_TWLP }, // 15 - EMUNAND3 O3DS TWLPSDCARD
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_CTRN_N }, // *1 - SYSNAND CTRNAND
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_TWLN }, // *2 - SYSNAND TWLN
|
||||
{ 0x000000, TYPE_SYSNAND, SUBTYPE_TWLP }, // *3 - SYSNAND TWLP
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_CTRN_N }, // *4 - EMUNAND0 N3DS CTRNAND
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_TWLN }, // *5 - EMUNAND0 N3DS TWLN
|
||||
{ 0x000000, TYPE_EMUNAND, SUBTYPE_TWLP }, // *6 - EMUNAND0 N3DS TWLP
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_CTRN_N }, // *7 - EMUNAND1 N3DS CTRNAND
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_TWLN }, // *8 - EMUNAND1 N3DS TWLN
|
||||
{ 0x400000, TYPE_EMUNAND, SUBTYPE_TWLP }, // *9 - EMUNAND1 N3DS TWLP
|
||||
{ 0x800000, TYPE_EMUNAND, SUBTYPE_CTRN_N }, // *10 - EMUNAND2 N3DS CTRNAND
|
||||
{ 0x800000, TYPE_EMUNAND, SUBTYPE_TWLN }, // *11 - EMUNAND2 N3DS TWLN
|
||||
{ 0x800000, TYPE_EMUNAND, SUBTYPE_TWLP }, // *12 - EMUNAND2 N3DS TWLP
|
||||
{ 0xC00000, TYPE_EMUNAND, SUBTYPE_CTRN_N }, // *13 - EMUNAND3 N3DS CTRNAND
|
||||
{ 0xC00000, TYPE_EMUNAND, SUBTYPE_TWLN }, // *14 - EMUNAND3 N3DS TWLN
|
||||
{ 0xC00000, TYPE_EMUNAND, SUBTYPE_TWLP } // *15 - EMUNAND3 N3DS TWLP
|
||||
};
|
||||
|
||||
SubtypeDesc SubTypes[4] = {
|
||||
{ 0x05CAE5, AES_CNT_CTRNAND_MODE, 0x4 }, // O3DS CTRNAND
|
||||
{ 0x05CAD7, AES_CNT_CTRNAND_MODE, 0x5 }, // N3DS CTRNAND
|
||||
{ 0x000097, AES_CNT_TWLNAND_MODE, 0x3 }, // TWLN
|
||||
{ 0x04808D, AES_CNT_TWLNAND_MODE, 0x3 } // TWLP
|
||||
};
|
||||
|
||||
static bool mode_n3ds = false;
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get counter for NAND AES decryption */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
u32 GetNandCtr(u8* ctr, u32 sector)
|
||||
{
|
||||
// static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
|
||||
static const u8* version_ctrs[] = {
|
||||
(u8*)0x080D7CAC,
|
||||
(u8*)0x080D858C,
|
||||
(u8*)0x080D748C,
|
||||
(u8*)0x080D740C,
|
||||
(u8*)0x080D74CC,
|
||||
(u8*)0x080D794C
|
||||
};
|
||||
static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);
|
||||
static u8* ctr_start = NULL;
|
||||
|
||||
if (ctr_start == NULL) {
|
||||
for (u32 i = 0; i < version_ctrs_len; i++) {
|
||||
if (*(u32*)version_ctrs[i] == 0x5C980) {
|
||||
ctr_start = (u8*) version_ctrs[i] + 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
// If value not in previous list start memory scanning (test range)
|
||||
if (ctr_start == NULL) {
|
||||
for (u8* c = (u8*) 0x080D8FFF; c > (u8*) 0x08000000; c--) {
|
||||
if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
|
||||
ctr_start = c + 0x30;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctr_start == NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// the ctr is stored backwards in memory
|
||||
if (sector >= (0x0B100000 / 0x200)) { // CTRNAND/AGBSAVE region
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
ctr[i] = *(ctr_start + (0xF - i));
|
||||
} else { // TWL region
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
ctr[i] = *(ctr_start + 0x88 + (0xF - i));
|
||||
}
|
||||
|
||||
// increment counter
|
||||
add_ctr(ctr, sector * (0x200/0x10));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -98,20 +177,37 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if ((pdrv >= 4) && mode_n3ds)
|
||||
pdrv += 12;
|
||||
if ((pdrv > 0) && mode_n3ds) // is this really set at this point?
|
||||
pdrv += 15;
|
||||
|
||||
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
||||
BYTE type = DriveInfo[pdrv].type;
|
||||
|
||||
if (type == TYPE_SDCARD) {
|
||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
} else {
|
||||
PartitionInfo* partition = GetPartitionInfo(DriveInfo[pdrv].subtype);
|
||||
if (partition == NULL) return RES_PARERR;
|
||||
u32 offset = (sector * 0x200) + partition->offset;
|
||||
SetNand(DriveInfo[pdrv].type == TYPE_EMUNAND, DriveInfo[pdrv].offset);
|
||||
if (DecryptNandToMem(buff, offset, count * 0x200, partition) != 0)
|
||||
BYTE subtype = DriveInfo[pdrv].subtype;
|
||||
DWORD isector = SubTypes[subtype].offset + sector;
|
||||
DWORD mode = SubTypes[subtype].mode;
|
||||
BYTE ctr[16] __attribute__((aligned(32)));
|
||||
|
||||
if (type == TYPE_SYSNAND) {
|
||||
if (sdmmc_nand_readsectors(isector, count, buff))
|
||||
return RES_PARERR;
|
||||
} else if (sdmmc_sdcard_readsectors(DriveInfo[pdrv].offset + isector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
GetNandCtr(ctr, isector);
|
||||
use_aeskey(SubTypes[subtype].keyslot);
|
||||
for (UINT s = 0; s < count; s++) {
|
||||
for (UINT b = 0x0; b < 0x200; b += 0x10, buff += 0x10) {
|
||||
set_ctr(ctr);
|
||||
aes_decrypt((void*) buff, (void*) buff, 1, mode);
|
||||
add_ctr(ctr, 0x1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
@ -132,21 +228,36 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if ((pdrv >= 4) && mode_n3ds)
|
||||
pdrv += 12;
|
||||
if ((pdrv > 0) && mode_n3ds)
|
||||
pdrv += 15;
|
||||
|
||||
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
} else {
|
||||
PartitionInfo* partition = GetPartitionInfo(DriveInfo[pdrv].subtype);
|
||||
if (partition == NULL) return RES_PARERR;
|
||||
u32 offset = (sector * 0x200) + partition->offset;
|
||||
SetNand(DriveInfo[pdrv].type == TYPE_EMUNAND, DriveInfo[pdrv].offset);
|
||||
// if (EncryptMemToNand(buff, offset, count * 0x200, partition) != 0)
|
||||
BYTE subtype = DriveInfo[pdrv].subtype;
|
||||
DWORD isector = SubTypes[subtype].offset + sector;
|
||||
DWORD mode = SubTypes[subtype].mode;
|
||||
BYTE ctr[16] __attribute__((aligned(32)));
|
||||
|
||||
GetNandCtr(ctr, isector);
|
||||
use_aeskey(SubTypes[subtype].keyslot);
|
||||
for (UINT s = 0; s < count; s++) {
|
||||
for (UINT b = 0x0; b < 0x200; b += 0x10, buff += 0x10) {
|
||||
set_ctr(ctr);
|
||||
aes_decrypt((void*) buff, (void*) buff, 1, mode);
|
||||
add_ctr(ctr, 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
/*if (type == TYPE_SYSNAND) {
|
||||
if (sdmmc_nand_writesectors(isector, count, buff))
|
||||
return RES_PARERR;
|
||||
// NO, not yet!
|
||||
} else if (sdmmc_sdcard_writesectors(DriveInfo[pdrv].offset + isector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}*/
|
||||
// stubbed, better be safe!
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
@ -169,8 +280,8 @@ DRESULT disk_ioctl (
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
if ((pdrv >= 4) && mode_n3ds)
|
||||
pdrv += 12;
|
||||
if ((pdrv > 0) && mode_n3ds)
|
||||
pdrv += 15;
|
||||
|
||||
switch (cmd) {
|
||||
case GET_SECTOR_SIZE:
|
||||
|
@ -1,220 +0,0 @@
|
||||
#include "platform.h"
|
||||
#include "fatfs/aes.h"
|
||||
#include "fatfs/nandio.h"
|
||||
#include "fatfs/sdmmc.h"
|
||||
|
||||
// see: http://3dbrew.org/wiki/Flash_Filesystem
|
||||
static PartitionInfo partitions[] = {
|
||||
{ "TWLN", {0xE9, 0x00, 0x00, 0x54, 0x57, 0x4C, 0x20, 0x20}, 0x00012E00, 0x08FB5200, 0x3, AES_CNT_TWLNAND_MODE },
|
||||
{ "TWLP", {0xE9, 0x00, 0x00, 0x54, 0x57, 0x4C, 0x20, 0x20}, 0x09011A00, 0x020B6600, 0x3, AES_CNT_TWLNAND_MODE },
|
||||
{ "AGBSAVE", {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x0B100000, 0x00030000, 0x7, AES_CNT_CTRNAND_MODE },
|
||||
{ "FIRM0", {0x46, 0x49, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00}, 0x0B130000, 0x00400000, 0x6, AES_CNT_CTRNAND_MODE },
|
||||
{ "FIRM1", {0x46, 0x49, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00}, 0x0B530000, 0x00400000, 0x6, AES_CNT_CTRNAND_MODE },
|
||||
{ "CTRNAND", {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}, 0x0B95CA00, 0x2F3E3600, 0x4, AES_CNT_CTRNAND_MODE }, // O3DS
|
||||
{ "CTRNAND", {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}, 0x0B95AE00, 0x41D2D200, 0x5, AES_CNT_CTRNAND_MODE } // N3DS
|
||||
};
|
||||
|
||||
static u32 emunand_header = 0;
|
||||
static u32 emunand_offset = 0;
|
||||
|
||||
|
||||
u32 CheckEmuNand(void)
|
||||
{
|
||||
u8 header[0x200];
|
||||
u32 nand_size_sectors = getMMCDevice(0)->total_size;
|
||||
u32 multi_sectors = (GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS;
|
||||
u32 ret = EMUNAND_NOT_READY;
|
||||
|
||||
// check the MBR for presence of a hidden partition
|
||||
sdmmc_sdcard_readsectors(0, 1, header);
|
||||
u32 hidden_sectors = getle32(header + 0x1BE + 0x8);
|
||||
|
||||
for (u32 offset_sector = 0; offset_sector + nand_size_sectors < hidden_sectors; offset_sector += multi_sectors) {
|
||||
// check for Gateway type EmuNAND
|
||||
sdmmc_sdcard_readsectors(offset_sector + nand_size_sectors, 1, header);
|
||||
if (memcmp(header + 0x100, "NCSD", 4) == 0) {
|
||||
ret |= EMUNAND_GATEWAY << (2 * (offset_sector / multi_sectors));
|
||||
continue;
|
||||
}
|
||||
// check for RedNAND type EmuNAND
|
||||
sdmmc_sdcard_readsectors(offset_sector + 1, 1, header);
|
||||
if (memcmp(header + 0x100, "NCSD", 4) == 0) {
|
||||
ret |= EMUNAND_REDNAND << (2 * (offset_sector / multi_sectors));
|
||||
continue;
|
||||
}
|
||||
// EmuNAND ready but not set up
|
||||
ret |= EMUNAND_READY << (2 * (offset_sector / multi_sectors));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SetNand(bool set_emunand, u32 base_sector)
|
||||
{
|
||||
// no checks here AT ALL - be careful!!!
|
||||
if (set_emunand) {
|
||||
emunand_header = base_sector + getMMCDevice(0)->total_size;
|
||||
emunand_offset = base_sector;
|
||||
} else {
|
||||
emunand_header = 0;
|
||||
emunand_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ReadNandSectors(u32 sector_no, u32 numsectors, u8 *out)
|
||||
{
|
||||
if (emunand_header) {
|
||||
if (sector_no == 0) {
|
||||
int errorcode = sdmmc_sdcard_readsectors(emunand_header, 1, out);
|
||||
if (errorcode) return errorcode;
|
||||
sector_no = 1;
|
||||
numsectors--;
|
||||
out += 0x200;
|
||||
}
|
||||
return sdmmc_sdcard_readsectors(sector_no + emunand_offset, numsectors, out);
|
||||
} else return sdmmc_nand_readsectors(sector_no, numsectors, out);
|
||||
}
|
||||
|
||||
int WriteNandSectors(u32 sector_no, u32 numsectors, u8 *in)
|
||||
{
|
||||
if (emunand_header) {
|
||||
if (sector_no == 0) {
|
||||
int errorcode = sdmmc_sdcard_writesectors(emunand_header, 1, in);
|
||||
if (errorcode) return errorcode;
|
||||
sector_no = 1;
|
||||
numsectors--;
|
||||
in += 0x200;
|
||||
}
|
||||
return sdmmc_sdcard_writesectors(sector_no + emunand_offset, numsectors, in);
|
||||
} else return sdmmc_nand_writesectors(sector_no, numsectors, in);
|
||||
}
|
||||
|
||||
u32 GetNandSize(void)
|
||||
{
|
||||
return getMMCDevice(0)->total_size * NAND_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
PartitionInfo* GetPartitionInfo(u32 partition_id)
|
||||
{
|
||||
u32 partition_num = 0;
|
||||
|
||||
if (partition_id == P_CTRNAND) {
|
||||
partition_num = (GetUnitPlatform() == PLATFORM_3DS) ? 5 : 6;
|
||||
} else {
|
||||
for(; !(partition_id & (1<<partition_num)) && (partition_num < 32); partition_num++);
|
||||
}
|
||||
|
||||
return (partition_num >= 32) ? NULL : &(partitions[partition_num]);
|
||||
}
|
||||
|
||||
u32 GetNandCtr(u8* ctr, u32 offset)
|
||||
{
|
||||
// static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
|
||||
static const u8* version_ctrs[] = {
|
||||
(u8*)0x080D7CAC,
|
||||
(u8*)0x080D858C,
|
||||
(u8*)0x080D748C,
|
||||
(u8*)0x080D740C,
|
||||
(u8*)0x080D74CC,
|
||||
(u8*)0x080D794C
|
||||
};
|
||||
static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);
|
||||
static u8* ctr_start = NULL;
|
||||
|
||||
if (ctr_start == NULL) {
|
||||
for (u32 i = 0; i < version_ctrs_len; i++) {
|
||||
if (*(u32*)version_ctrs[i] == 0x5C980) {
|
||||
ctr_start = (u8*) version_ctrs[i] + 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
// If value not in previous list start memory scanning (test range)
|
||||
if (ctr_start == NULL) {
|
||||
for (u8* c = (u8*) 0x080D8FFF; c > (u8*) 0x08000000; c--) {
|
||||
if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
|
||||
ctr_start = c + 0x30;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctr_start == NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// the ctr is stored backwards in memory
|
||||
if (offset >= 0x0B100000) { // CTRNAND/AGBSAVE region
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
ctr[i] = *(ctr_start + (0xF - i));
|
||||
} else { // TWL region
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
ctr[i] = *(ctr_start + 0x88 + (0xF - i));
|
||||
}
|
||||
|
||||
// increment counter
|
||||
add_ctr(ctr, offset / 0x10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CryptBuffer(CryptBufferInfo *info)
|
||||
{
|
||||
u8 ctr[16] __attribute__((aligned(32)));
|
||||
memcpy(ctr, info->ctr, 16);
|
||||
|
||||
u8* buffer = info->buffer;
|
||||
u32 size = info->size;
|
||||
u32 mode = info->mode;
|
||||
|
||||
if (info->setKeyY) {
|
||||
u8 keyY[16] __attribute__((aligned(32)));
|
||||
memcpy(keyY, info->keyY, 16);
|
||||
setup_aeskeyY(info->keyslot, keyY);
|
||||
info->setKeyY = 0;
|
||||
}
|
||||
use_aeskey(info->keyslot);
|
||||
|
||||
for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
|
||||
set_ctr(ctr);
|
||||
if ((mode & (0x7 << 27)) == AES_CBC_DECRYPT_MODE)
|
||||
memcpy(ctr, buffer, 0x10);
|
||||
aes_decrypt((void*) buffer, (void*) buffer, 1, mode);
|
||||
if ((mode & (0x7 << 27)) == AES_CBC_ENCRYPT_MODE)
|
||||
memcpy(ctr, buffer, 0x10);
|
||||
else if ((mode & (0x7 << 27)) == AES_CTR_MODE)
|
||||
add_ctr(ctr, 0x1);
|
||||
}
|
||||
|
||||
memcpy(info->ctr, ctr, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 DecryptNandToMem(u8* buffer, u32 offset, u32 size, PartitionInfo* partition)
|
||||
{
|
||||
CryptBufferInfo info = {.keyslot = partition->keyslot, .setKeyY = 0, .size = size, .buffer = buffer, .mode = partition->mode};
|
||||
if(GetNandCtr(info.ctr, offset) != 0)
|
||||
return 1;
|
||||
|
||||
u32 n_sectors = (size + NAND_SECTOR_SIZE - 1) / NAND_SECTOR_SIZE;
|
||||
u32 start_sector = offset / NAND_SECTOR_SIZE;
|
||||
ReadNandSectors(start_sector, n_sectors, buffer);
|
||||
CryptBuffer(&info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 EncryptMemToNand(u8* buffer, u32 offset, u32 size, PartitionInfo* partition)
|
||||
{
|
||||
CryptBufferInfo info = {.keyslot = partition->keyslot, .setKeyY = 0, .size = size, .buffer = buffer, .mode = partition->mode};
|
||||
if(GetNandCtr(info.ctr, offset) != 0)
|
||||
return 1;
|
||||
|
||||
u32 n_sectors = (size + NAND_SECTOR_SIZE - 1) / NAND_SECTOR_SIZE;
|
||||
u32 start_sector = offset / NAND_SECTOR_SIZE;
|
||||
CryptBuffer(&info);
|
||||
WriteNandSectors(start_sector, n_sectors, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define BUFFER_ADDRESS ((u8*) 0x21000000) // buffer must not be used for anything else!
|
||||
#define BUFFER_MAX_SIZE (1 * 1024 * 1024) // must be a multiple of 0x40 (64)
|
||||
|
||||
#define NAND_SECTOR_SIZE 0x200
|
||||
#define SECTORS_PER_READ (BUFFER_MAX_SIZE / NAND_SECTOR_SIZE)
|
||||
|
||||
#define P_TWLN (1<<0)
|
||||
#define P_TWLP (1<<1)
|
||||
#define P_AGBSAVE (1<<2)
|
||||
#define P_FIRM0 (1<<3)
|
||||
#define P_FIRM1 (1<<4)
|
||||
#define P_CTRNAND (1<<5)
|
||||
|
||||
// return values for the CheckEmuNAND() function
|
||||
#define EMUNAND_NOT_READY 0 // must be zero
|
||||
#define EMUNAND_READY 1
|
||||
#define EMUNAND_GATEWAY 2
|
||||
#define EMUNAND_REDNAND 3
|
||||
|
||||
// these offsets are used by Multi EmuNAND Creator
|
||||
#define EMUNAND_MULTI_OFFSET_O3DS 0x00200000
|
||||
#define EMUNAND_MULTI_OFFSET_N3DS 0x00400000
|
||||
|
||||
typedef struct {
|
||||
u32 keyslot;
|
||||
u32 setKeyY;
|
||||
u8 ctr[16];
|
||||
u8 keyY[16];
|
||||
u32 size;
|
||||
u32 mode;
|
||||
u8* buffer;
|
||||
} __attribute__((packed)) CryptBufferInfo;
|
||||
|
||||
typedef struct {
|
||||
char name[16];
|
||||
u8 magic[8];
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 keyslot;
|
||||
u32 mode;
|
||||
} __attribute__((packed)) PartitionInfo;
|
||||
|
||||
PartitionInfo* GetPartitionInfo(u32 partition_id);
|
||||
|
||||
u32 CheckEmuNand(void);
|
||||
void SetNand(bool set_emunand, u32 base_sector);
|
||||
|
||||
u32 GetNandCtr(u8* ctr, u32 offset);
|
||||
u32 CryptBuffer(CryptBufferInfo *info);
|
||||
|
||||
int ReadNandSectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int WriteNandSectors(u32 sector_no, u32 numsectors, u8 *in);
|
||||
u32 GetNandSize(void);
|
||||
|
||||
u32 DecryptNandToMem(u8* buffer, u32 offset, u32 size, PartitionInfo* partition);
|
||||
u32 EncryptMemToNand(u8* buffer, u32 offset, u32 size, PartitionInfo* partition);
|
@ -1,7 +1,6 @@
|
||||
#include "draw.h"
|
||||
#include "fs.h"
|
||||
#include "fatfs/ff.h"
|
||||
#include "fatfs/nandio.h"
|
||||
|
||||
// don't use this area for anything else!
|
||||
static FATFS* fs = (FATFS*)0x20316000;
|
||||
|
@ -41,7 +41,10 @@ u32 GodMode() {
|
||||
u32 offset_disp = 0;
|
||||
|
||||
ClearScreenFull(true, true, COLOR_BLACK);
|
||||
if (!InitFS()) return exit_mode;
|
||||
if (!InitFS()) {
|
||||
InputWait();
|
||||
return exit_mode;
|
||||
}
|
||||
|
||||
contents = GetDirContents("");
|
||||
while (true) { // this is the main loop
|
||||
|
Loading…
x
Reference in New Issue
Block a user