mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Use actual offsets from NCSD in virtual drives
This commit is contained in:
parent
90049a5fd3
commit
48281307a0
@ -5,6 +5,7 @@
|
||||
#include "keydb.h"
|
||||
#include "aes.h"
|
||||
#include "sha.h"
|
||||
#include "fatmbr.h"
|
||||
#include "sdmmc.h"
|
||||
#include "image.h"
|
||||
|
||||
@ -13,6 +14,19 @@
|
||||
#define KEY95_SHA256 ((IS_DEVKIT) ? slot0x11Key95dev_sha256 : slot0x11Key95_sha256)
|
||||
#define SECTOR_SHA256 ((IS_DEVKIT) ? sector0x96dev_sha256 : sector0x96_sha256)
|
||||
|
||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||
static const u32 np_keyslots[9][4] = { // [NP_TYPE][NP_SUBTYPE]
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // none
|
||||
{ 0xFF, 0x03, 0x04, 0x05 }, // standard
|
||||
{ 0xFF, 0x03, 0x04, 0x05 }, // FAT (custom, not in NCSD)
|
||||
{ 0xFF, 0xFF, 0x06, 0xFF }, // FIRM
|
||||
{ 0xFF, 0xFF, 0x07, 0xFF }, // AGBSAVE
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // NCSD (custom)
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // D0K3 (custom)
|
||||
{ 0xFF, 0xFF, 0xFF, 0x11 }, // SECRET (custom)
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF } // BONUS (custom)
|
||||
};
|
||||
|
||||
static u8 slot0x05KeyY[0x10] = { 0x00 }; // need to load this from FIRM0 / external file
|
||||
static const u8 slot0x05KeyY_sha256[0x20] = { // hash for slot0x05KeyY (16 byte)
|
||||
0x98, 0x24, 0x27, 0x14, 0x22, 0xB0, 0x6B, 0xF2, 0x10, 0x96, 0x9C, 0x36, 0x42, 0x53, 0x7C, 0x86,
|
||||
@ -96,23 +110,24 @@ static u32 emunand_base_sector = 0x000000;
|
||||
|
||||
u32 LoadKeyYFromP9(u8* key, const u8* keyhash, u32 offset, u32 keyslot)
|
||||
{
|
||||
static u32 offsetA9l = 0x066A00; // fixed offset, this only has to work for FIRM90 / FIRM81
|
||||
static const u32 offsetA9l = 0x066A00; // fixed offset, this only has to work for FIRM90 / FIRM81
|
||||
static const u32 sector_firm0 = 0x058980; // standard firm0 sector (this only has to work in A9LH anyways)
|
||||
u8 ctr0x15[16] __attribute__((aligned(32)));
|
||||
u8 keyY0x15[16] __attribute__((aligned(32)));
|
||||
u8 keyY[16] __attribute__((aligned(32)));
|
||||
u8 header[0x200];
|
||||
|
||||
// check arm9loaderhax
|
||||
if (!IS_A9LH || (offset < (offsetA9l + 0x0800))) return 1;
|
||||
if (!IS_A9LH || IS_SIGHAX || (offset < (offsetA9l + 0x0800))) return 1;
|
||||
|
||||
// section 2 (arm9loader) header of FIRM
|
||||
// this is @0x066A00 in FIRM90 & FIRM81
|
||||
ReadNandBytes(header, (SECTOR_FIRM0 * 0x200) + offsetA9l, 0x200, 0x06, NAND_SYSNAND);
|
||||
ReadNandBytes(header, (sector_firm0 * 0x200) + offsetA9l, 0x200, 0x06, NAND_SYSNAND);
|
||||
memcpy(keyY0x15, header + 0x10, 0x10); // 0x15 keyY
|
||||
memcpy(ctr0x15, header + 0x20, 0x10); // 0x15 counter
|
||||
|
||||
// read and decrypt the encrypted keyY
|
||||
ReadNandBytes(keyY, (SECTOR_FIRM0 * 0x200) + offset, 0x10, 0x06, NAND_SYSNAND);
|
||||
ReadNandBytes(keyY, (sector_firm0 * 0x200) + offset, 0x10, 0x06, NAND_SYSNAND);
|
||||
setup_aeskeyY(0x15, keyY0x15);
|
||||
use_aeskey(0x15);
|
||||
ctr_decrypt_byte(keyY, keyY, 0x10, offset - (offsetA9l + 0x800), AES_CNT_CTRNAND_MODE, ctr0x15);
|
||||
@ -141,6 +156,7 @@ bool InitNandCrypto(void)
|
||||
// store the current SHA256 from register
|
||||
memcpy(OtpSha256, (void*) REG_SHAHASH, 32);
|
||||
} else {
|
||||
// load hash via keys?
|
||||
const char* base[] = { INPUT_PATHS };
|
||||
char path[64];
|
||||
u8 otp[0x100];
|
||||
@ -231,18 +247,18 @@ bool CheckSlot0x05Crypto(void)
|
||||
bool CheckSector0x96Crypto(void)
|
||||
{
|
||||
u8 buffer[0x200];
|
||||
ReadNandSectors(buffer, 0x96, 1, 0x11, NAND_SYSNAND);
|
||||
ReadNandSectors(buffer, SECTOR_SECRET, 1, 0x11, NAND_SYSNAND);
|
||||
return (sha_cmp(KEY95_SHA256, buffer, 16, SHA256_MODE) == 0);
|
||||
}
|
||||
|
||||
void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot)
|
||||
{
|
||||
u32 mode = (sector >= SECTOR_TWL + SIZE_TWL) ? AES_CNT_CTRNAND_MODE : AES_CNT_TWLNAND_MODE;
|
||||
u32 mode = (keyslot != 0x03) ? AES_CNT_CTRNAND_MODE : AES_CNT_TWLNAND_MODE; // somewhat hacky
|
||||
u8 ctr[16] __attribute__((aligned(32)));
|
||||
u32 blocks = count * (0x200 / 0x10);
|
||||
|
||||
// copy NAND CTR and increment it
|
||||
memcpy(ctr, (sector >= SECTOR_TWL + SIZE_TWL) ? CtrNandCtr : TwlNandCtr, 16);
|
||||
memcpy(ctr, (keyslot != 0x03) ? CtrNandCtr : TwlNandCtr, 16); // hacky again
|
||||
add_ctr(ctr, sector * (0x200 / 0x10));
|
||||
|
||||
// decrypt the data
|
||||
@ -356,7 +372,7 @@ int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_src
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if ((keyslot == 0x11) && (sector == 0x96)) CryptSector0x96(buffer, false);
|
||||
if ((keyslot == 0x11) && (sector == SECTOR_SECRET)) CryptSector0x96(buffer, false);
|
||||
else if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot);
|
||||
|
||||
return 0;
|
||||
@ -368,7 +384,7 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n
|
||||
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 == 0x11) && (sector == 0x96)) CryptSector0x96(NAND_BUFFER, true);
|
||||
if ((keyslot == 0x11) && (sector == SECTOR_SECRET)) CryptSector0x96(NAND_BUFFER, true);
|
||||
else if (keyslot < 0x40) CryptNand(NAND_BUFFER, sector + s, pcount, keyslot);
|
||||
if (nand_dst == NAND_EMUNAND) {
|
||||
int errorcode = 0;
|
||||
@ -391,6 +407,94 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetNandNcsdMinSizeSectors(NandNcsdHeader* ncsd) // in sectors
|
||||
{
|
||||
u32 nand_minsize = 1;
|
||||
for (u32 prt_idx = 0; prt_idx < 8; prt_idx++) {
|
||||
u32 prt_end = ncsd->partitions[prt_idx].offset + ncsd->partitions[prt_idx].size;
|
||||
if (prt_end > nand_minsize) nand_minsize = prt_end;
|
||||
}
|
||||
|
||||
return nand_minsize;
|
||||
}
|
||||
|
||||
u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index, NandNcsdHeader* ncsd)
|
||||
{
|
||||
// safety / set keyslot
|
||||
if ((type == NP_TYPE_FAT) || (type > NP_TYPE_BONUS) || (subtype > NP_SUBTYPE_CTR_N)) return 1;
|
||||
info->keyslot = np_keyslots[type][subtype];
|
||||
|
||||
// full (minimum) NAND "partition"
|
||||
if (type == NP_TYPE_NONE) {
|
||||
info->sector = 0x00;
|
||||
info->count = GetNandNcsdMinSizeSectors(ncsd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// special, custom partition types, not in NCSD
|
||||
if (type >= NP_TYPE_NCSD) {
|
||||
if (type == NP_TYPE_NCSD) {
|
||||
info->sector = 0x00; // hardcoded
|
||||
info->count = 0x01;
|
||||
} else if (type == NP_TYPE_D0K3) {
|
||||
info->sector = SECTOR_D0K3; // hardcoded
|
||||
info->count = SECTOR_SECRET - info->sector;
|
||||
} else if (type == NP_TYPE_SECRET) {
|
||||
info->sector = SECTOR_SECRET;
|
||||
info->count = 0x01;
|
||||
} else if (type == NP_TYPE_BONUS) {
|
||||
info->sector = GetNandNcsdMinSizeSectors(ncsd);
|
||||
info->count = 0x00; // placeholder, actual size needs info from NAND chip
|
||||
} else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 prt_idx = 8;
|
||||
for (prt_idx = 0; prt_idx < 8; prt_idx++) {
|
||||
if ((ncsd->partitions_fs_type[prt_idx] != type) ||
|
||||
(ncsd->partitions_crypto_type[prt_idx] != subtype)) continue;
|
||||
if (index == 0) break;
|
||||
index--;
|
||||
}
|
||||
|
||||
if (prt_idx >= 8) return 1; // not found
|
||||
info->sector = ncsd->partitions[prt_idx].offset;
|
||||
info->count = ncsd->partitions[prt_idx].size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetNandPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index, u32 nand_src)
|
||||
{
|
||||
// check NAND NCSD integrity(!!!)
|
||||
// workaround for ZERONAND
|
||||
if (nand_src == NAND_ZERONAND) nand_src = NAND_SYSNAND;
|
||||
|
||||
// find type & subtype in NCSD header
|
||||
u8 header[0x200];
|
||||
ReadNandSectors(header, 0x00, 1, 0xFF, nand_src);
|
||||
NandNcsdHeader* ncsd = (NandNcsdHeader*) header;
|
||||
if (((type == NP_TYPE_FAT) && (GetNandNcsdPartitionInfo(info, NP_TYPE_STD, subtype, 0, ncsd) != 0)) ||
|
||||
((type != NP_TYPE_FAT) && (GetNandNcsdPartitionInfo(info, type, subtype, index, ncsd) != 0)))
|
||||
return 1; // not found
|
||||
|
||||
// size of bonus partition
|
||||
if (type == NP_TYPE_BONUS) {
|
||||
info->count = GetNandSizeSectors(nand_src) - info->sector;
|
||||
} else if (type == NP_TYPE_FAT) { // FAT type specific stuff
|
||||
ReadNandSectors(header, info->sector, 1, info->keyslot, nand_src);
|
||||
MbrHeader* mbr = (MbrHeader*) header;
|
||||
if ((ValidateMbrHeader(mbr) != 0) || (index >= 4) ||
|
||||
(mbr->partitions[index].sector == 0) || (mbr->partitions[index].count == 0) ||
|
||||
(mbr->partitions[index].sector + mbr->partitions[index].count > info->count))
|
||||
return 1;
|
||||
info->sector += mbr->partitions[index].sector;
|
||||
info->count = mbr->partitions[index].count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 CheckNandMbr(u8* mbr)
|
||||
{
|
||||
if (memcmp(mbr + (0x200 - sizeof(twl_mbr)), twl_mbr, sizeof(twl_mbr)) == 0)
|
||||
@ -470,7 +574,7 @@ u32 GetLegitSector0x96(u8* sector)
|
||||
// search for valid secret sector in SysNAND / EmuNAND
|
||||
const u32 nand_src[] = { NAND_SYSNAND, NAND_EMUNAND };
|
||||
for (u32 i = 0; i < sizeof(nand_src) / sizeof(u32); i++) {
|
||||
ReadNandSectors(sector, 0x96, 1, 0x11, nand_src[i]);
|
||||
ReadNandSectors(sector, SECTOR_SECRET, 1, 0x11, nand_src[i]);
|
||||
if (sha_cmp(SECTOR_SHA256, sector, 0x200, SHA256_MODE) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
// start sectors of partitions
|
||||
#define SECTOR_TWL 0x000000
|
||||
#define SECTOR_D0K3 0x000001
|
||||
#define SECTOR_SECRET 0x000096
|
||||
#define SECTOR_TWLN 0x000097
|
||||
#define SECTOR_TWLP 0x04808D
|
||||
@ -39,7 +40,52 @@
|
||||
#define SECTOR_NAME "sector0x96.bin"
|
||||
#define SECRET_NAME "secret_sector.bin"
|
||||
#define OTP_NAME "otp.bin"
|
||||
#define OTP_BIG_NAME "otp0x108.bin"
|
||||
#define OTP_BIG_NAME "otp0x108.bin"
|
||||
|
||||
// 0x110...0x118 in the NAND NCSD header
|
||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||
#define NP_TYPE_NONE 0
|
||||
#define NP_TYPE_STD 1
|
||||
#define NP_TYPE_FAT 2 // this is of our own making
|
||||
#define NP_TYPE_FIRM 3
|
||||
#define NP_TYPE_AGB 4
|
||||
#define NP_TYPE_NCSD 5 // this is of our own making
|
||||
#define NP_TYPE_D0K3 6 // my own partition ^_^
|
||||
#define NP_TYPE_SECRET 7 // this is of our own making
|
||||
#define NP_TYPE_BONUS 8 // this is of our own making
|
||||
|
||||
// 0x118...0x120 in the NAND NCSD header
|
||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||
#define NP_SUBTYPE_NONE 0
|
||||
#define NP_SUBTYPE_TWL 1
|
||||
#define NP_SUBTYPE_CTR 2
|
||||
#define NP_SUBTYPE_CTR_N 3
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 sector;
|
||||
u32 count;
|
||||
u32 keyslot;
|
||||
} __attribute__((packed)) NandPartitionInfo;
|
||||
|
||||
typedef struct {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
} __attribute__((packed)) NandNcsdPartition;
|
||||
|
||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||
typedef struct {
|
||||
u8 signature[0x100];
|
||||
u8 magic[4];
|
||||
u32 size;
|
||||
u64 mediaId; // this is zero
|
||||
u8 partitions_fs_type[8];
|
||||
u8 partitions_crypto_type[8];
|
||||
NandNcsdPartition partitions[8];
|
||||
u8 unknown[0x5E];
|
||||
u8 twl_mbr[0x42];
|
||||
} __attribute__((packed)) NandNcsdHeader;
|
||||
|
||||
|
||||
bool InitNandCrypto(void);
|
||||
bool CheckSlot0x05Crypto(void);
|
||||
@ -52,7 +98,10 @@ int WriteNandBytes(const u8* buffer, u64 offset, u64 count, u32 keyslot, u32 nan
|
||||
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);
|
||||
|
||||
u32 GetNandNcsdMinSizeSectors(NandNcsdHeader* ncsd);
|
||||
u64 GetNandSizeSectors(u32 src);
|
||||
u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index, NandNcsdHeader* ncsd);
|
||||
u32 GetNandPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 index, u32 nand_src);
|
||||
u64 GetNandUnusedSectors(u32 src);
|
||||
u32 CheckNandMbr(u8* mbr);
|
||||
u32 CheckNandHeader(u8* header);
|
||||
|
@ -4,40 +4,45 @@
|
||||
#include "essentials.h"
|
||||
#include "unittype.h"
|
||||
|
||||
#define VFLAG_ON_O3DS NAND_TYPE_O3DS
|
||||
#define VFLAG_ON_N3DS NAND_TYPE_N3DS
|
||||
#define VFLAG_ON_NO3DS NAND_TYPE_NO3DS
|
||||
#define VFLAG_ON_NAND (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS)
|
||||
#define VFLAG_MBR (1UL<<27)
|
||||
#define VFLAG_ESSENTIAL (1UL<<28)
|
||||
#define VFLAG_GBA_VC (1UL<<29)
|
||||
#define VFLAG_NEEDS_OTP (1UL<<30)
|
||||
#define VFLAG_NAND_SIZE (1UL<<31)
|
||||
|
||||
// see: http://3dbrew.org/wiki/Flash_Filesystem#NAND_structure
|
||||
// too much hardcoding, but more readable this way
|
||||
static const VirtualFile vNandFileTemplates[] = {
|
||||
{ "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_NAND },
|
||||
{ "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_NAND },
|
||||
{ "agbsave.bin" , 0x0B100000, 0x00030000, 0x07, VFLAG_ON_NAND },
|
||||
{ "firm0.bin" , 0x0B130000, 0x00400000, 0x06, VFLAG_ON_NAND},
|
||||
{ "firm1.bin" , 0x0B530000, 0x00400000, 0x06, VFLAG_ON_NAND},
|
||||
{ "ctrnand_fat.bin" , 0x0B95CA00, 0x2F3E3600, 0x04, VFLAG_ON_O3DS },
|
||||
{ "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x05, VFLAG_ON_N3DS },
|
||||
{ "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x04, VFLAG_ON_NO3DS },
|
||||
{ "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS },
|
||||
{ "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS },
|
||||
{ "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS },
|
||||
{ "sector0x96.bin" , 0x00012C00, 0x00000200, 0x11, VFLAG_ON_NAND | VFLAG_NEEDS_OTP },
|
||||
{ "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_NAND | VFLAG_NAND_SIZE },
|
||||
{ "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS },
|
||||
{ "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS },
|
||||
{ "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_NAND },
|
||||
{ "twlmbr.bin" , 0x000001BE, 0x00000042, 0x03, VFLAG_ON_NAND },
|
||||
{ "free0x01.bin" , 0x00000200, 0x00012A00, 0xFF, VFLAG_ON_NAND },
|
||||
{ "essential.exefs" , 0x00000200, 0x00000000, 0xFF, VFLAG_ON_NAND | VFLAG_ESSENTIAL },
|
||||
{ "bonus0x1D7800.bin", 0x3AF00000, 0x00000000, 0xFF, VFLAG_ON_O3DS | VFLAG_NAND_SIZE },
|
||||
{ "bonus0x26C000.bin", 0x4D800000, 0x00000000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS | VFLAG_NAND_SIZE },
|
||||
{ "gbavc.sav" , 0x0B100200, 0x00000000, 0x07, VFLAG_ON_NAND | VFLAG_GBA_VC },
|
||||
typedef struct {
|
||||
char name[32];
|
||||
u32 type;
|
||||
u32 subtype;
|
||||
u32 index;
|
||||
u32 flags;
|
||||
} __attribute__((packed)) VirtualNandTemplate;
|
||||
|
||||
// see NP_TYPE_ and NP_SUBTYPE_ in nand.h
|
||||
static const VirtualNandTemplate vNandTemplates[] = {
|
||||
{ "nand_hdr.bin" , NP_TYPE_NCSD , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "twlmbr.bin" , NP_TYPE_STD , NP_SUBTYPE_TWL , 0, VFLAG_MBR },
|
||||
{ "essential.exefs" , NP_TYPE_D0K3 , NP_SUBTYPE_NONE , 0, VFLAG_ESSENTIAL },
|
||||
{ "sector0x96.bin" , NP_TYPE_SECRET, NP_SUBTYPE_CTR_N, 0, VFLAG_NEEDS_OTP },
|
||||
{ "twln.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 0, 0 },
|
||||
{ "twlp.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 1, 0 },
|
||||
{ "agbsave.bin" , NP_TYPE_AGB , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "gbavc.sav" , NP_TYPE_AGB , NP_SUBTYPE_CTR , 0, VFLAG_GBA_VC },
|
||||
{ "firm0.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "firm1.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 1, 0 },
|
||||
{ "firm2.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 2, 0 },
|
||||
{ "firm3.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 3, 0 },
|
||||
{ "firm4.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 4, 0 },
|
||||
{ "firm5.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 5, 0 },
|
||||
{ "firm6.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 6, 0 },
|
||||
{ "firm7.bin" , NP_TYPE_FIRM , NP_SUBTYPE_CTR , 7, 0 },
|
||||
{ "ctrnand_full.bin" , NP_TYPE_STD , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "ctrnand_full.bin" , NP_TYPE_STD , NP_SUBTYPE_CTR_N, 0, 0 },
|
||||
{ "ctrnand_fat.bin" , NP_TYPE_FAT , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "ctrnand_fat.bin" , NP_TYPE_FAT , NP_SUBTYPE_CTR_N, 0, 0 },
|
||||
{ "bonus.bin" , NP_TYPE_BONUS , NP_SUBTYPE_CTR , 0, 0 },
|
||||
{ "nand.bin" , NP_TYPE_NONE , NP_SUBTYPE_NONE , 0, VFLAG_NAND_SIZE },
|
||||
{ "nand_minsize.bin" , NP_TYPE_NONE , NP_SUBTYPE_NONE , 0, 0 }
|
||||
};
|
||||
|
||||
bool CheckVNandDrive(u32 nand_src) {
|
||||
@ -45,35 +50,38 @@ bool CheckVNandDrive(u32 nand_src) {
|
||||
}
|
||||
|
||||
bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir object generated in virtual.c
|
||||
int n_templates = sizeof(vNandFileTemplates) / sizeof(VirtualFile);
|
||||
const VirtualFile* templates = vNandFileTemplates;
|
||||
int n_templates = sizeof(vNandTemplates) / sizeof(VirtualNandTemplate);
|
||||
const VirtualNandTemplate* templates = vNandTemplates;
|
||||
u32 nand_src = vdir->flags & VRT_SOURCE;
|
||||
|
||||
while (++vdir->index < n_templates) {
|
||||
// get NAND type (O3DS/N3DS/NO3DS), workaround for empty EmuNAND
|
||||
u32 nand_type = CheckNandType(nand_src);
|
||||
if (!nand_type) nand_type = (IS_O3DS) ? NAND_TYPE_O3DS : NAND_TYPE_N3DS;
|
||||
while (++vdir->index < n_templates) {
|
||||
const VirtualNandTemplate* template = templates + vdir->index;
|
||||
NandPartitionInfo prt_info;
|
||||
|
||||
// copy current template to vfile
|
||||
memcpy(vfile, templates + vdir->index, sizeof(VirtualFile));
|
||||
// set up virtual file
|
||||
if (GetNandPartitionInfo(&prt_info, template->type, template->subtype, template->index, nand_src) != 0)
|
||||
continue;
|
||||
snprintf(vfile->name, 32, "%s%s", template->name, (nand_src == VRT_XORPAD) ? ".xorpad" : "");
|
||||
vfile->offset = ((u64) prt_info.sector) * 0x200;
|
||||
vfile->size = ((u64) prt_info.count) * 0x200;
|
||||
vfile->keyslot = prt_info.keyslot;
|
||||
vfile->flags = template->flags;
|
||||
|
||||
// XORpad drive handling
|
||||
if (nand_src == VRT_XORPAD) {
|
||||
snprintf(vfile->name, 32, "%s.xorpad", templates[vdir->index].name);
|
||||
if ((vfile->keyslot == 0x11) || (vfile->keyslot >= 0x40) || (vfile->flags & VFLAG_GBA_VC))
|
||||
continue;
|
||||
}
|
||||
|
||||
// process / check special flags
|
||||
if (!(vfile->flags & nand_type))
|
||||
continue; // virtual file has wrong NAND type
|
||||
// handle special cases
|
||||
if (!vfile->size) continue;
|
||||
if ((nand_src == VRT_XORPAD) && ((vfile->keyslot == 0x11) || (vfile->keyslot >= 0x40) || (vfile->flags & VFLAG_GBA_VC)))
|
||||
continue;
|
||||
if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto())
|
||||
continue; // keyslot 0x05 not properly set up
|
||||
if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto())
|
||||
continue; // sector 0x96 crypto not set up
|
||||
if (vfile->flags & VFLAG_MBR) {
|
||||
vfile->offset += 0x200 - 0x42;
|
||||
vfile->size = 0x42;
|
||||
}
|
||||
if (vfile->flags & VFLAG_NAND_SIZE) {
|
||||
if ((nand_src != VRT_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src)))
|
||||
continue; // EmuNAND/ImgNAND is too small
|
||||
if ((nand_src != VRT_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) > GetNandSizeSectors(nand_src)))
|
||||
continue; // EmuNAND / ImgNAND is too small
|
||||
u64 nand_size = GetNandSizeSectors(NAND_SYSNAND) * 0x200;
|
||||
if (nand_size <= vfile->offset) continue;
|
||||
vfile->size = nand_size - vfile->offset;
|
||||
@ -87,9 +95,11 @@ bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir
|
||||
}
|
||||
if (vfile->flags & VFLAG_GBA_VC) {
|
||||
if (CheckAgbSaveCmac(nand_src) != 0) continue;
|
||||
vfile->offset += 0x200;
|
||||
vfile->size = GetAgbSaveSize(nand_src);
|
||||
}
|
||||
|
||||
|
||||
// found if arriving here
|
||||
vfile->flags |= nand_src;
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user