aboutsummaryrefslogtreecommitdiff
path: root/src/DSi_NAND.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DSi_NAND.cpp')
-rw-r--r--src/DSi_NAND.cpp236
1 files changed, 109 insertions, 127 deletions
diff --git a/src/DSi_NAND.cpp b/src/DSi_NAND.cpp
index 7c3e745..03bed9b 100644
--- a/src/DSi_NAND.cpp
+++ b/src/DSi_NAND.cpp
@@ -22,6 +22,7 @@
#include "DSi.h"
#include "DSi_AES.h"
#include "DSi_NAND.h"
+#include "FATIO.h"
#include "Platform.h"
#include "sha1/sha1.hpp"
@@ -34,78 +35,16 @@ using namespace Platform;
namespace DSi_NAND
{
-FileHandle* CurFile;
-FATFS CurFS;
-
-u8 eMMC_CID[16];
-u64 ConsoleID;
-
-u8 FATIV[16];
-u8 FATKey[16];
-
-u8 ESKey[16];
-
-
-UINT FF_ReadNAND(BYTE* buf, LBA_t sector, UINT num);
-UINT FF_WriteNAND(BYTE* buf, LBA_t sector, UINT num);
-
-
-bool Init(u8* es_keyY)
+NANDImage::NANDImage(Platform::FileHandle* nandfile, const DSiKey& es_keyY) noexcept : NANDImage(nandfile, es_keyY.data())
{
- CurFile = nullptr;
-
- std::string nandpath = Platform::GetConfigString(Platform::DSi_NANDPath);
- std::string instnand = nandpath + Platform::InstanceFileSuffix();
-
- FileHandle* nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWriteExisting);
- if ((!nandfile) && (Platform::InstanceID() > 0))
- {
- FileHandle* orig = Platform::OpenLocalFile(nandpath, FileMode::Read);
- if (!orig)
- {
- Log(LogLevel::Error, "Failed to open DSi NAND\n");
- return false;
- }
-
- long len = FileLength(orig);
-
- nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWrite);
- if (nandfile)
- {
- u8* tmpbuf = new u8[0x10000];
- for (long i = 0; i < len; i+=0x10000)
- {
- long blklen = 0x10000;
- if ((i+blklen) > len) blklen = len-i;
-
- FileRead(tmpbuf, blklen, 1, orig);
- FileWrite(tmpbuf, blklen, 1, nandfile);
- }
- delete[] tmpbuf;
- }
-
- Platform::CloseFile(orig);
- Platform::CloseFile(nandfile);
-
- nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWriteExisting);
- }
+}
+NANDImage::NANDImage(Platform::FileHandle* nandfile, const u8* es_keyY) noexcept
+{
if (!nandfile)
- return false;
-
- u64 nandlen = FileLength(nandfile);
-
- ff_disk_open(FF_ReadNAND, FF_WriteNAND, (LBA_t)(nandlen>>9));
+ return;
- FRESULT res;
- res = f_mount(&CurFS, "0:", 0);
- if (res != FR_OK)
- {
- Log(LogLevel::Error, "NAND mounting failed: %d\n", res);
- f_unmount("0:");
- ff_disk_close();
- return false;
- }
+ Length = FileLength(nandfile);
// read the nocash footer
@@ -113,26 +52,24 @@ bool Init(u8* es_keyY)
char nand_footer[16];
const char* nand_footer_ref = "DSi eMMC CID/CPU";
- FileRead(nand_footer, 1, 16, nandfile);
- if (memcmp(nand_footer, nand_footer_ref, 16))
+ FileRead(nand_footer, 1, sizeof(nand_footer), nandfile);
+ if (memcmp(nand_footer, nand_footer_ref, sizeof(nand_footer)))
{
// There is another copy of the footer at 000FF800h for the case
// that by external tools the image was cut off
// See https://problemkaputt.de/gbatek.htm#dsisdmmcimages
FileSeek(nandfile, 0x000FF800, FileSeekOrigin::Start);
- FileRead(nand_footer, 1, 16, nandfile);
- if (memcmp(nand_footer, nand_footer_ref, 16))
+ FileRead(nand_footer, 1, sizeof(nand_footer), nandfile);
+ if (memcmp(nand_footer, nand_footer_ref, sizeof(nand_footer)))
{
Log(LogLevel::Error, "ERROR: NAND missing nocash footer\n");
CloseFile(nandfile);
- f_unmount("0:");
- ff_disk_close();
- return false;
+ return;
}
}
- FileRead(eMMC_CID, 1, 16, nandfile);
- FileRead(&ConsoleID, 1, 8, nandfile);
+ FileRead(eMMC_CID.data(), 1, sizeof(eMMC_CID), nandfile);
+ FileRead(&ConsoleID, 1, sizeof(ConsoleID), nandfile);
// init NAND crypto
@@ -141,10 +78,10 @@ bool Init(u8* es_keyY)
u8 keyX[16], keyY[16];
SHA1Init(&sha);
- SHA1Update(&sha, eMMC_CID, 16);
+ SHA1Update(&sha, eMMC_CID.data(), sizeof(eMMC_CID));
SHA1Final(tmp, &sha);
- Bswap128(FATIV, tmp);
+ Bswap128(FATIV.data(), tmp);
*(u32*)&keyX[0] = (u32)ConsoleID;
*(u32*)&keyX[4] = (u32)ConsoleID ^ 0x24EE6906;
@@ -157,7 +94,7 @@ bool Init(u8* es_keyY)
*(u32*)&keyY[12] = 0xE1A00005;
DSi_AES::DeriveNormalKey(keyX, keyY, tmp);
- Bswap128(FATKey, tmp);
+ Bswap128(FATKey.data(), tmp);
*(u32*)&keyX[0] = 0x4E00004A;
@@ -165,42 +102,87 @@ bool Init(u8* es_keyY)
*(u32*)&keyX[8] = (u32)(ConsoleID >> 32) ^ 0xC80C4B72;
*(u32*)&keyX[12] = (u32)ConsoleID;
- memcpy(keyY, es_keyY, 16);
+ memcpy(keyY, es_keyY, sizeof(keyY));
DSi_AES::DeriveNormalKey(keyX, keyY, tmp);
- Bswap128(ESKey, tmp);
+ Bswap128(ESKey.data(), tmp);
CurFile = nandfile;
- return true;
}
-void DeInit()
+NANDImage::~NANDImage()
{
- f_unmount("0:");
- ff_disk_close();
-
if (CurFile) CloseFile(CurFile);
CurFile = nullptr;
}
+NANDImage::NANDImage(NANDImage&& other) noexcept :
+ CurFile(other.CurFile),
+ eMMC_CID(other.eMMC_CID),
+ ConsoleID(other.ConsoleID),
+ FATIV(other.FATIV),
+ FATKey(other.FATKey),
+ ESKey(other.ESKey)
+{
+ other.CurFile = nullptr;
+}
+
+NANDImage& NANDImage::operator=(NANDImage&& other) noexcept
+{
+ if (this != &other)
+ {
+ CurFile = other.CurFile;
+ eMMC_CID = other.eMMC_CID;
+ ConsoleID = other.ConsoleID;
+ FATIV = other.FATIV;
+ FATKey = other.FATKey;
+ ESKey = other.ESKey;
+
+ other.CurFile = nullptr;
+ }
+
+ return *this;
+}
-FileHandle* GetFile()
+NANDMount::NANDMount(NANDImage& nand) noexcept : Image(&nand)
{
- return CurFile;
+ if (!nand)
+ return;
+
+ CurFS = std::make_unique<FATFS>();
+ ff_disk_open(
+ [this](BYTE* buf, LBA_t sector, UINT num) {
+ return this->FF_ReadNAND(buf, sector, num);
+ },
+ [this](const BYTE* buf, LBA_t sector, UINT num) {
+ return this->FF_WriteNAND(buf, sector, num);
+ },
+ (LBA_t)(nand.GetLength()>>9)
+ );
+
+ FRESULT res;
+ res = f_mount(CurFS.get(), "0:", 0);
+ if (res != FR_OK)
+ {
+ Log(LogLevel::Error, "NAND mounting failed: %d\n", res);
+ f_unmount("0:");
+ ff_disk_close();
+ return;
+ }
}
-void GetIDs(u8* emmc_cid, u64& consoleid)
+NANDMount::~NANDMount()
{
- memcpy(emmc_cid, eMMC_CID, 16);
- consoleid = ConsoleID;
+ f_unmount("0:");
+ ff_disk_close();
}
-void SetupFATCrypto(AES_ctx* ctx, u32 ctr)
+void NANDImage::SetupFATCrypto(AES_ctx* ctx, u32 ctr)
{
u8 iv[16];
- memcpy(iv, FATIV, sizeof(iv));
+ memcpy(iv, FATIV.data(), sizeof(iv));
u32 res;
res = iv[15] + (ctr & 0xFF);
@@ -218,10 +200,10 @@ void SetupFATCrypto(AES_ctx* ctx, u32 ctr)
else break;
}
- AES_init_ctx_iv(ctx, FATKey, iv);
+ AES_init_ctx_iv(ctx, FATKey.data(), iv);
}
-u32 ReadFATBlock(u64 addr, u32 len, u8* buf)
+u32 NANDImage::ReadFATBlock(u64 addr, u32 len, u8* buf)
{
u32 ctr = (u32)(addr >> 4);
@@ -243,7 +225,7 @@ u32 ReadFATBlock(u64 addr, u32 len, u8* buf)
return len;
}
-u32 WriteFATBlock(u64 addr, u32 len, u8* buf)
+u32 NANDImage::WriteFATBlock(u64 addr, u32 len, const u8* buf)
{
u32 ctr = (u32)(addr >> 4);
@@ -272,30 +254,30 @@ u32 WriteFATBlock(u64 addr, u32 len, u8* buf)
}
-UINT FF_ReadNAND(BYTE* buf, LBA_t sector, UINT num)
+UINT NANDMount::FF_ReadNAND(BYTE* buf, LBA_t sector, UINT num)
{
// TODO: allow selecting other partitions?
u64 baseaddr = 0x10EE00;
u64 blockaddr = baseaddr + (sector * 0x200ULL);
- u32 res = ReadFATBlock(blockaddr, num*0x200, buf);
+ u32 res = Image->ReadFATBlock(blockaddr, num*0x200, buf);
return res >> 9;
}
-UINT FF_WriteNAND(BYTE* buf, LBA_t sector, UINT num)
+UINT NANDMount::FF_WriteNAND(const BYTE* buf, LBA_t sector, UINT num)
{
// TODO: allow selecting other partitions?
u64 baseaddr = 0x10EE00;
u64 blockaddr = baseaddr + (sector * 0x200ULL);
- u32 res = WriteFATBlock(blockaddr, num*0x200, buf);
+ u32 res = Image->WriteFATBlock(blockaddr, num*0x200, buf);
return res >> 9;
}
-bool ESEncrypt(u8* data, u32 len)
+bool NANDImage::ESEncrypt(u8* data, u32 len) const
{
AES_ctx ctx;
u8 iv[16];
@@ -307,7 +289,7 @@ bool ESEncrypt(u8* data, u32 len)
iv[14] = 0x00;
iv[15] = 0x01;
- AES_init_ctx_iv(&ctx, ESKey, iv);
+ AES_init_ctx_iv(&ctx, ESKey.data(), iv);
u32 blklen = (len + 0xF) & ~0xF;
mac[0] = 0x3A;
@@ -380,7 +362,7 @@ bool ESEncrypt(u8* data, u32 len)
return true;
}
-bool ESDecrypt(u8* data, u32 len)
+bool NANDImage::ESDecrypt(u8* data, u32 len)
{
AES_ctx ctx;
u8 iv[16];
@@ -392,7 +374,7 @@ bool ESDecrypt(u8* data, u32 len)
iv[14] = 0x00;
iv[15] = 0x01;
- AES_init_ctx_iv(&ctx, ESKey, iv);
+ AES_init_ctx_iv(&ctx, ESKey.data(), iv);
u32 blklen = (len + 0xF) & ~0xF;
mac[0] = 0x3A;
@@ -486,7 +468,7 @@ bool ESDecrypt(u8* data, u32 len)
}
-void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
+void NANDMount::ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
{
FF_FIL file;
FRESULT res;
@@ -508,7 +490,7 @@ void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
}
-void ReadUserData(DSiFirmwareSystemSettings& data)
+void NANDMount::ReadUserData(DSiFirmwareSystemSettings& data)
{
FF_FIL file;
FRESULT res;
@@ -557,7 +539,7 @@ void ReadUserData(DSiFirmwareSystemSettings& data)
f_close(&file);
}
-void PatchUserData()
+void NANDMount::PatchUserData()
{
FRESULT res;
@@ -653,7 +635,7 @@ void debug_listfiles(const char* path)
f_closedir(&dir);
}
-bool ImportFile(const char* path, const u8* data, size_t len)
+bool NANDMount::ImportFile(const char* path, const u8* data, size_t len)
{
if (!data || !len || !path)
return false;
@@ -687,7 +669,7 @@ bool ImportFile(const char* path, const u8* data, size_t len)
return true;
}
-bool ImportFile(const char* path, const char* in)
+bool NANDMount::ImportFile(const char* path, const char* in)
{
FF_FIL file;
FILE* fin;
@@ -730,7 +712,7 @@ bool ImportFile(const char* path, const char* in)
return true;
}
-bool ExportFile(const char* path, const char* out)
+bool NANDMount::ExportFile(const char* path, const char* out)
{
FF_FIL file;
FILE* fout;
@@ -771,7 +753,7 @@ bool ExportFile(const char* path, const char* out)
return true;
}
-void RemoveFile(const char* path)
+void NANDMount::RemoveFile(const char* path)
{
FF_FILINFO info;
FRESULT res = f_stat(path, &info);
@@ -784,7 +766,7 @@ void RemoveFile(const char* path)
Log(LogLevel::Debug, "Removed file at %s\n", path);
}
-void RemoveDir(const char* path)
+void NANDMount::RemoveDir(const char* path)
{
FF_DIR dir;
FF_FILINFO info;
@@ -839,7 +821,7 @@ void RemoveDir(const char* path)
}
-u32 GetTitleVersion(u32 category, u32 titleid)
+u32 NANDMount::GetTitleVersion(u32 category, u32 titleid)
{
FRESULT res;
char path[256];
@@ -859,7 +841,7 @@ u32 GetTitleVersion(u32 category, u32 titleid)
return version;
}
-void ListTitles(u32 category, std::vector<u32>& titlelist)
+void NANDMount::ListTitles(u32 category, std::vector<u32>& titlelist)
{
FRESULT res;
FF_DIR titledir;
@@ -908,7 +890,7 @@ void ListTitles(u32 category, std::vector<u32>& titlelist)
f_closedir(&titledir);
}
-bool TitleExists(u32 category, u32 titleid)
+bool NANDMount::TitleExists(u32 category, u32 titleid)
{
char path[256];
snprintf(path, sizeof(path), "0:/title/%08x/%08x/content/title.tmd", category, titleid);
@@ -917,7 +899,7 @@ bool TitleExists(u32 category, u32 titleid)
return (res == FR_OK);
}
-void GetTitleInfo(u32 category, u32 titleid, u32& version, NDSHeader* header, NDSBanner* banner)
+void NANDMount::GetTitleInfo(u32 category, u32 titleid, u32& version, NDSHeader* header, NDSBanner* banner)
{
version = GetTitleVersion(category, titleid);
if (version == 0xFFFFFFFF)
@@ -953,7 +935,7 @@ void GetTitleInfo(u32 category, u32 titleid, u32& version, NDSHeader* header, ND
}
-bool CreateTicket(const char* path, u32 titleid0, u32 titleid1, u8 version)
+bool NANDMount::CreateTicket(const char* path, u32 titleid0, u32 titleid1, u8 version)
{
FF_FIL file;
FRESULT res;
@@ -979,7 +961,7 @@ bool CreateTicket(const char* path, u32 titleid0, u32 titleid1, u8 version)
memset(&ticket[0x222], 0xFF, 0x20);
- ESEncrypt(ticket, 0x2A4);
+ Image->ESEncrypt(ticket, 0x2A4);
f_write(&file, ticket, 0x2C4, &nwrite);
@@ -988,7 +970,7 @@ bool CreateTicket(const char* path, u32 titleid0, u32 titleid1, u8 version)
return true;
}
-bool CreateSaveFile(const char* path, u32 len)
+bool NANDMount::CreateSaveFile(const char* path, u32 len)
{
if (len == 0) return true;
if (len < 0x200) return false;
@@ -1078,7 +1060,7 @@ bool CreateSaveFile(const char* path, u32 len)
return true;
}
-bool InitTitleFileStructure(const NDSHeader& header, const DSi_TMD::TitleMetadata& tmd, bool readonly)
+bool NANDMount::InitTitleFileStructure(const NDSHeader& header, const DSi_TMD::TitleMetadata& tmd, bool readonly)
{
u32 titleid0 = tmd.GetCategory();
u32 titleid1 = tmd.GetID();
@@ -1158,7 +1140,7 @@ bool InitTitleFileStructure(const NDSHeader& header, const DSi_TMD::TitleMetadat
return true;
}
-bool ImportTitle(const char* appfile, const DSi_TMD::TitleMetadata& tmd, bool readonly)
+bool NANDMount::ImportTitle(const char* appfile, const DSi_TMD::TitleMetadata& tmd, bool readonly)
{
NDSHeader header {};
{
@@ -1196,7 +1178,7 @@ bool ImportTitle(const char* appfile, const DSi_TMD::TitleMetadata& tmd, bool re
return true;
}
-bool ImportTitle(const u8* app, size_t appLength, const DSi_TMD::TitleMetadata& tmd, bool readonly)
+bool NANDMount::ImportTitle(const u8* app, size_t appLength, const DSi_TMD::TitleMetadata& tmd, bool readonly)
{
if (!app || appLength < sizeof(NDSHeader))
return false;
@@ -1232,7 +1214,7 @@ bool ImportTitle(const u8* app, size_t appLength, const DSi_TMD::TitleMetadata&
return true;
}
-void DeleteTitle(u32 category, u32 titleid)
+void NANDMount::DeleteTitle(u32 category, u32 titleid)
{
char fname[128];
@@ -1243,7 +1225,7 @@ void DeleteTitle(u32 category, u32 titleid)
RemoveDir(fname);
}
-u32 GetTitleDataMask(u32 category, u32 titleid)
+u32 NANDMount::GetTitleDataMask(u32 category, u32 titleid)
{
u32 version;
NDSHeader header;
@@ -1260,7 +1242,7 @@ u32 GetTitleDataMask(u32 category, u32 titleid)
return ret;
}
-bool ImportTitleData(u32 category, u32 titleid, int type, const char* file)
+bool NANDMount::ImportTitleData(u32 category, u32 titleid, int type, const char* file)
{
char fname[128];
@@ -1286,7 +1268,7 @@ bool ImportTitleData(u32 category, u32 titleid, int type, const char* file)
return ImportFile(fname, file);
}
-bool ExportTitleData(u32 category, u32 titleid, int type, const char* file)
+bool NANDMount::ExportTitleData(u32 category, u32 titleid, int type, const char* file)
{
char fname[128];