diff options
Diffstat (limited to 'src/DSi_NAND.cpp')
-rw-r--r-- | src/DSi_NAND.cpp | 236 |
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]; |