123 lines
5.3 KiB
C
Raw Normal View History

#include "vnand.h"
#include "nand.h"
#include "agbsave.h"
#include "essentials.h"
2017-02-26 13:35:37 +01:00
#include "unittype.h"
#define VFLAG_MBR (1UL<<27)
#define VFLAG_ESSENTIAL (1UL<<28)
2017-02-17 15:54:37 +01:00
#define VFLAG_GBA_VC (1UL<<29)
#define VFLAG_NEEDS_OTP (1UL<<30)
#define VFLAG_NAND_SIZE (1UL<<31)
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_DELETABLE | 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, VFLAG_DELETABLE },
{ "gbavc.sav" , NP_TYPE_AGB , NP_SUBTYPE_CTR , 0, VFLAG_DELETABLE | 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, VFLAG_DELETABLE },
{ "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) {
return GetNandSizeSectors(nand_src);
}
2016-11-28 16:30:49 +01:00
bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir object generated in virtual.c
int n_templates = sizeof(vNandTemplates) / sizeof(VirtualNandTemplate);
const VirtualNandTemplate* templates = vNandTemplates;
2016-12-21 00:31:21 +01:00
u32 nand_src = vdir->flags & VRT_SOURCE;
while (++vdir->index < n_templates) {
const VirtualNandTemplate* template = templates + vdir->index;
NandPartitionInfo prt_info;
2016-11-15 23:06:01 +01:00
// set up virtual file
if (template->flags & VFLAG_NAND_SIZE) { // override for "nand.bin"
prt_info.sector = 0;
prt_info.count = GetNandSizeSectors(nand_src);
prt_info.keyslot = 0xFF;
} else 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;
2016-12-02 15:42:05 +01:00
// handle special cases
if (!vfile->size) continue;
if ((nand_src == VRT_XORPAD) && ((vfile->keyslot == 0x11) || (vfile->keyslot >= 0x40) || (vfile->flags & VFLAG_GBA_VC)))
continue;
2016-11-15 23:06:01 +01:00
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_ESSENTIAL) {
const u8 magic[] = { ESSENTIAL_MAGIC };
u8 data[sizeof(magic)];
ReadNandBytes(data, vfile->offset, sizeof(magic), vfile->keyslot, nand_src);
if (memcmp(data, magic, sizeof(magic)) != 0) continue;
vfile->size = sizeof(EssentialBackup);
2016-11-15 23:06:01 +01:00
}
if (vfile->flags & VFLAG_GBA_VC) {
if (CheckAgbSaveCmac(nand_src) != 0) continue;
vfile->offset += 0x200;
vfile->size = GetAgbSaveSize(nand_src);
}
2016-11-15 23:06:01 +01:00
2016-11-15 23:06:01 +01:00
// found if arriving here
vfile->flags |= nand_src;
return true;
}
2016-11-15 23:06:01 +01:00
return false;
}
int ReadVNandFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
2016-12-02 15:42:05 +01:00
u32 nand_src = vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD);
return ReadNandBytes(buffer, vfile->offset + offset, count, vfile->keyslot, nand_src);
}
int WriteVNandFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count) {
2016-12-02 15:42:05 +01:00
u32 nand_dst = vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD);
int res = WriteNandBytes(buffer, vfile->offset + offset, count, vfile->keyslot, nand_dst);
if ((res == 0) && (vfile->flags & VFLAG_GBA_VC)) res = FixAgbSaveCmac(nand_dst);
return res;
}
2017-01-17 23:24:46 +01:00
u64 GetVNandDriveSize(u32 nand_src) {
return GetNandSizeSectors(nand_src) * 0x200;
}