mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
126 lines
5.5 KiB
C
126 lines
5.5 KiB
C
#include "vnand.h"
|
|
#include "nand.h"
|
|
#include "agbsave.h"
|
|
#include "essentials.h"
|
|
#include "unittype.h"
|
|
|
|
#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)
|
|
|
|
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) {
|
|
return GetNandSizeSectors(nand_src);
|
|
}
|
|
|
|
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;
|
|
u32 nand_src = vdir->flags & VRT_SOURCE;
|
|
|
|
while (++vdir->index < n_templates) {
|
|
const VirtualNandTemplate* template = templates + vdir->index;
|
|
NandPartitionInfo prt_info;
|
|
|
|
// 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;
|
|
|
|
// 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
|
|
u64 nand_size = GetNandSizeSectors(NAND_SYSNAND) * 0x200;
|
|
if (nand_size <= vfile->offset) continue;
|
|
vfile->size = nand_size - vfile->offset;
|
|
}
|
|
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);
|
|
}
|
|
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;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u64 offset, u64 count) {
|
|
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 u8* buffer, u64 offset, u64 count) {
|
|
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;
|
|
}
|
|
|
|
u64 GetVNandDriveSize(u32 nand_src) {
|
|
return GetNandSizeSectors(nand_src) * 0x200;
|
|
}
|